import type { AnimationCycleType, CameraPresetId, EngineeringFact, GuidedTourStep, MachineAnimationDescriptor, MachineAssetDescriptor, MachineCategory, MachineDefinition, MachinePart, MachinePartRole, MachineSeoMetadata, Vector3Tuple, } from '../schema'; const vec = (x: number, y: number, z: number): Vector3Tuple => [x, y, z]; const categoryThumbnails = { engines: '/thumbnails/engines.svg', gearboxes: '/thumbnails/gearboxes.svg', pumps: '/thumbnails/pumps.svg', mechanisms: '/thumbnails/mechanisms.svg', structural: '/thumbnails/structural.svg', } satisfies Record; const roleColors: Record = { housing: '#657289', rotating: '#4C8DFF', reciprocating: '#FFB04C', valve: '#46D39A', fastener: '#94A3B8', fluid: '#38BDF8', sensor: '#C084FC', control: '#F97316', bearing: '#D7DEE8', brake: '#F87171', electrical: '#FACC15', annotation: '#FFFFFF', }; const materialForRole = (role: MachinePartRole): string => { switch (role) { case 'housing': return 'cast aluminium / iron reference material'; case 'rotating': return 'hardened alloy steel reference material'; case 'reciprocating': return 'forged steel or aluminium reference material'; case 'valve': return 'stainless heat-resistant steel reference material'; case 'fastener': return 'zinc-plated steel reference material'; case 'fluid': return 'animated translucent flow volume'; case 'sensor': return 'instrumented indicator material'; case 'control': return 'machined control linkage material'; case 'bearing': return 'bearing-grade chromium steel reference material'; case 'brake': return 'high-friction composite reference material'; case 'electrical': return 'insulated copper / ceramic reference material'; case 'annotation': return 'non-physical annotation overlay'; } }; const part = ( id: string, name: string, description: string, role: MachinePartRole, explode: Vector3Tuple, options: Partial = {}, ): MachinePart => { const explodeVector = options.explode ?? explode; return { id, name, description, role, material: options.material ?? materialForRole(role), color: options.color ?? roleColors[role], defaultVisible: options.defaultVisible ?? true, defaultOpacity: options.defaultOpacity ?? 1, visible: options.visible ?? options.defaultVisible ?? true, opacity: options.opacity ?? options.defaultOpacity ?? 1, selectable: options.selectable ?? true, parentId: options.parentId, transform: options.transform, explode: explodeVector, annotation: options.annotation ?? { label: name, offset: vec(explodeVector[0] * 0.32, explodeVector[1] * 0.32 + 0.08, explodeVector[2] * 0.32), }, specs: options.specs ?? {}, tags: options.tags ?? [], }; }; const fact = (label: string, value: string, description?: string, unit?: string): EngineeringFact => ({ label, value, description, unit, }); type TourSeed = { id: string; title: string; body: string; parts: readonly string[]; preset?: CameraPresetId; durationSeconds?: number; cue?: string; }; const tour = (steps: readonly TourSeed[]): GuidedTourStep[] => steps.map((step) => ({ id: step.id, title: step.title, body: step.body, focusPartIds: step.parts, cameraPreset: step.preset ?? 'isometric', durationSeconds: step.durationSeconds ?? 6, highlightColor: '#FFB04C', animationCue: step.cue, })); const animation = ( moduleName: string, cycleType: AnimationCycleType, defaultRpm: number, minRpm: number, maxRpm: number, stepCount: number, drivenParts: readonly string[], notes: readonly string[], revolutionsPerCycle = 1, parameters: MachineAnimationDescriptor['parameters'] = {}, ): MachineAnimationDescriptor => ({ modulePath: `src/animations/machines/${moduleName}.ts`, defaultRpm, minRpm, maxRpm, cycleSeconds: Number(((60 / defaultRpm) * revolutionsPerCycle).toFixed(4)), cycleType, loopMode: 'seamless', stepCount, drivenParts, notes, ...(Object.keys(parameters).length > 0 ? { parameters } : {}), }); const asset = (id: string, boundingRadius: number): MachineAssetDescriptor => ({ strategy: 'procedural', status: 'procedural-placeholder', source: `Mechanica procedural reference geometry package for ${id}; production GLB handoff will replace this descriptor without changing core viewer code.`, license: 'Project-owned educational reference asset', draco: false, ktx2: false, scale: 1, center: vec(0, 0, 0), boundingRadius, variants: [ { id: 'reference-procedural', label: 'Reference procedural geometry', quality: 'procedural', polygonBudget: 18000, textureBudgetMb: 0, }, ], }); type MachineSeed = Omit< MachineDefinition, | 'slug' | 'name' | 'summary' | 'keyFacts' | 'engineeringFacts' | 'tour' | 'image' | 'dateAdded' | 'updatedAt' | 'seo' | 'phase' | 'thumbnailAlt' > & { slug?: string; name?: string; summary?: string; keyFacts?: readonly EngineeringFact[]; engineeringFacts?: readonly EngineeringFact[]; tour?: readonly GuidedTourStep[]; image?: string; dateAdded?: string; updatedAt?: string; seo?: Partial; phase?: 1 | 2; thumbnailAlt?: string; }; const defineMachine = (seed: MachineSeed): MachineDefinition => { const seo: MachineSeoMetadata = { title: seed.seo?.title ?? `${seed.title} | Mechanica`, description: seed.seo?.description ?? seed.description, shareImage: seed.seo?.shareImage ?? seed.thumbnail, keywords: seed.seo?.keywords ?? seed.keywords, }; return { ...seed, phase: seed.phase ?? 1, slug: seed.slug ?? seed.id, name: seed.name ?? seed.title, summary: seed.summary ?? seed.subtitle, keyFacts: seed.keyFacts ?? seed.facts, engineeringFacts: seed.engineeringFacts ?? seed.facts, tour: seed.tour ?? seed.guidedTour, image: seed.image ?? seed.thumbnail, dateAdded: seed.dateAdded ?? seed.createdAt, updatedAt: seed.updatedAt ?? seed.createdAt, thumbnailAlt: seed.thumbnailAlt ?? `${seed.title} technical thumbnail`, seo, } as MachineDefinition; }; export const coreMachineDefinitions = [ defineMachine({ id: 'four-stroke-petrol-engine', title: 'Four Stroke Petrol Engine', subtitle: 'Spark-ignition piston engine with intake, compression, combustion, and exhaust strokes.', category: 'engines', difficulty: 'beginner', complexity: 6, releaseOrder: 1, createdAt: '2025-01-01', thumbnail: categoryThumbnails.engines, tags: ['engine', 'otto cycle', 'spark ignition', 'piston'], keywords: ['four stroke', 'petrol', 'gasoline', 'otto', 'valve', 'piston', 'crankshaft'], description: 'A four stroke petrol engine converts an air-fuel charge into crankshaft torque over two crankshaft revolutions. The model is structured around the cylinder, valve train, piston group, and crank train so learners can isolate each stroke and observe how valve timing and crank geometry coordinate.', facts: [ fact('Cycle length', '720° crank rotation', 'One complete thermodynamic cycle requires two crankshaft revolutions.'), fact('Typical speed', '700-6,500 rpm', 'Automotive passenger engines idle near 700 rpm and peak far higher.'), fact('Thermal efficiency', '25-35%', 'Modern naturally aspirated spark-ignition engines commonly sit in this range.'), fact('Invented', '1876', 'Nikolaus Otto demonstrated the practical four-stroke cycle.'), fact('Common applications', 'Cars, motorcycles, generators', 'Used where throttle response and compact power density matter.'), ], parts: [ part('cylinder-block', 'Cylinder block', 'Rigid casting that locates the cylinder bore, coolant jacket, and crankcase loads.', 'housing', vec(-0.4, 0, 0)), part('piston', 'Piston', 'Sealed reciprocating element that receives gas pressure and drives the connecting rod.', 'reciprocating', vec(0, 0.8, 0)), part('connecting-rod', 'Connecting rod', 'Pinned link that converts piston motion into crankshaft rotation.', 'reciprocating', vec(0.25, 0.35, 0)), part('crankshaft', 'Crankshaft', 'Offset shaft that transforms reciprocating force into useful rotary torque.', 'rotating', vec(0, -0.55, 0)), part('camshaft', 'Camshaft', 'Timed shaft with lobes that actuate intake and exhaust valves.', 'rotating', vec(0, 1.15, -0.35)), part('intake-valve', 'Intake valve', 'Popppet valve that admits fresh air-fuel charge during the intake stroke.', 'valve', vec(-0.35, 1.2, 0.2)), part('exhaust-valve', 'Exhaust valve', 'Poppet valve that opens for burned-gas scavenging during exhaust.', 'valve', vec(0.35, 1.2, 0.2)), part('spark-plug', 'Spark plug', 'Insulated electrode that initiates combustion near top dead centre.', 'electrical', vec(0, 1.45, 0.15)), part('flywheel', 'Flywheel', 'Rotational inertia that smooths torque between power strokes.', 'rotating', vec(0.85, -0.45, 0)), ], guidedTour: tour([ { id: 'cycle-overview', title: 'Four distinct strokes', body: 'Follow the piston as the crankshaft completes two revolutions: intake, compression, power, and exhaust.', parts: ['piston', 'crankshaft', 'connecting-rod'], preset: 'front', cue: 'cycle-scrub', }, { id: 'breathing', title: 'Timed breathing', body: 'The camshaft opens the intake and exhaust valves at different crank angles to control gas exchange.', parts: ['camshaft', 'intake-valve', 'exhaust-valve'], preset: 'top', }, { id: 'combustion-event', title: 'Ignition and torque', body: 'The spark plug fires near top dead centre, pressure rises, and the connecting rod transmits force to the crank throw.', parts: ['spark-plug', 'piston', 'crankshaft'], }, ]), related: ['two-stroke-engine', 'diesel-engine', 'v8-engine', 'slider-crank'], animation: animation( 'fourStrokePetrolEngine', 'hybrid', 900, 300, 6500, 4, ['piston', 'connecting-rod', 'crankshaft', 'camshaft', 'intake-valve', 'exhaust-valve', 'spark-plug'], [ 'Piston completes one power event every two crankshaft revolutions.', 'Camshaft turns at half crankshaft speed.', 'Valve lift curves are eased with sinusoidal ramps to avoid visual discontinuities.', ], 2, ), asset: asset('four-stroke-petrol-engine', 3.2), learningObjectives: [ 'Identify the four strokes and their crank angle ranges.', 'Explain why the camshaft rotates at half crank speed.', 'Relate piston force to crankshaft torque.', ], }), defineMachine({ id: 'two-stroke-engine', title: 'Two Stroke Engine', subtitle: 'Port-controlled engine that completes a power cycle every crankshaft revolution.', category: 'engines', difficulty: 'beginner', complexity: 5, releaseOrder: 2, createdAt: '2025-01-02', thumbnail: categoryThumbnails.engines, tags: ['engine', 'two stroke', 'ports', 'crankcase scavenging'], keywords: ['two stroke', 'transfer port', 'exhaust port', 'reed valve', 'scavenging'], description: 'A two stroke engine combines intake, compression, combustion, and exhaust events into one crankshaft revolution. The foundation model emphasizes port timing, crankcase pre-compression, and the trade-off between high power density and mixture short-circuiting.', facts: [ fact('Cycle length', '360° crank rotation', 'A firing event can occur on every crank revolution.'), fact('Typical speed', '2,000-12,000 rpm', 'Small engines and racing applications often operate at high speed.'), fact('Power density', 'High', 'Fewer strokes per power event increase output per displacement.'), fact('Key limitation', 'Scavenging losses', 'Fresh charge can escape through the exhaust port.'), fact('Common applications', 'Chainsaws, scooters, marine outboards', 'Used where simplicity and weight are critical.'), ], parts: [ part('cylinder', 'Cylinder', 'Bore with intake transfer and exhaust ports opened directly by piston motion.', 'housing', vec(-0.35, 0.25, 0)), part('piston', 'Piston', 'Controls port opening while compressing charge above and below itself.', 'reciprocating', vec(0, 0.75, 0)), part('crankcase', 'Crankcase', 'Sealed lower volume used to pre-compress incoming mixture.', 'housing', vec(0, -0.4, 0)), part('transfer-port', 'Transfer port', 'Passage that routes pre-compressed mixture from crankcase to cylinder.', 'fluid', vec(-0.55, 0.3, 0.2)), part('exhaust-port', 'Exhaust port', 'Window uncovered by the piston to release burned gases.', 'fluid', vec(0.55, 0.3, 0.2)), part('reed-valve', 'Reed valve', 'One-way flexible inlet valve that prevents blowback into the carburettor.', 'valve', vec(-0.65, -0.2, 0.1)), part('spark-plug', 'Spark plug', 'Ignition source for the compressed air-fuel charge.', 'electrical', vec(0, 1.2, 0.1)), part('crankshaft', 'Crankshaft', 'Single-throw shaft coupled to the piston through a connecting rod.', 'rotating', vec(0, -0.75, 0)), ], guidedTour: tour([ { id: 'one-revolution-cycle', title: 'One revolution cycle', body: 'The piston uncovers ports at carefully phased heights so gas exchange and power happen in a compact cycle.', parts: ['piston', 'transfer-port', 'exhaust-port'], preset: 'front', }, { id: 'crankcase-pump', title: 'Crankcase pumping', body: 'Downward piston travel pressurizes the crankcase and pushes fresh mixture up through transfer passages.', parts: ['crankcase', 'reed-valve', 'transfer-port'], }, { id: 'port-overlap', title: 'Scavenging compromise', body: 'The exhaust port opens before the transfer port; this helps clear burned gas but can waste fresh charge.', parts: ['exhaust-port', 'transfer-port'], }, ]), related: ['four-stroke-petrol-engine', 'wankel-rotary-engine', 'scotch-yoke'], animation: animation( 'twoStrokeEngine', 'hybrid', 3000, 800, 12000, 3, ['piston', 'crankshaft', 'reed-valve'], [ 'Port visibility masks are tied to piston crown height.', 'Flow arrows reverse only at reed-valve pressure thresholds.', ], ), asset: asset('two-stroke-engine', 2.8), learningObjectives: [ 'Compare one-revolution and two-revolution engine cycles.', 'Describe how piston-controlled ports replace cam-driven valves.', 'Explain crankcase scavenging.', ], }), defineMachine({ id: 'diesel-engine', title: 'Diesel Engine', subtitle: 'Compression-ignition piston engine using high-pressure fuel injection.', category: 'engines', difficulty: 'intermediate', complexity: 7, releaseOrder: 3, createdAt: '2025-01-03', thumbnail: categoryThumbnails.engines, tags: ['engine', 'diesel', 'compression ignition', 'injector'], keywords: ['diesel', 'injector', 'compression ignition', 'common rail', 'glow plug'], description: 'A diesel engine ignites fuel by injecting it into air heated by high compression. This model separates the air path, piston bowl, injector plume, and fuel rail so learners can study compression ignition and the reasons diesel engines produce high low-speed torque.', facts: [ fact('Ignition method', 'Compression ignition', 'No spark is required once operating temperature is reached.'), fact('Compression ratio', '14:1-22:1', 'Higher than petrol engines to raise air temperature before injection.'), fact('Thermal efficiency', '35-45%', 'Large slow-speed diesels can exceed this range.'), fact('Invented', '1890s', 'Rudolf Diesel patented the compression ignition engine.'), fact('Common applications', 'Trucks, ships, generators, heavy equipment'), ], parts: [ part('cylinder-block', 'Cylinder block', 'High-strength casting sized for elevated compression pressures.', 'housing', vec(-0.45, 0, 0)), part('piston-bowl', 'Piston bowl', 'Shaped combustion bowl that promotes air swirl and fuel mixing.', 'reciprocating', vec(0, 0.82, 0)), part('crankshaft', 'Crankshaft', 'Robust crankshaft designed for high cylinder pressure and torque.', 'rotating', vec(0, -0.65, 0)), part('connecting-rod', 'Connecting rod', 'Heavy-duty link transferring piston load to the crankshaft.', 'reciprocating', vec(0.22, 0.35, 0)), part('intake-valve', 'Intake valve', 'Admits clean air without premixed fuel.', 'valve', vec(-0.35, 1.18, 0.2)), part('exhaust-valve', 'Exhaust valve', 'Releases hot exhaust gases after expansion.', 'valve', vec(0.35, 1.18, 0.2)), part('common-rail-injector', 'Common-rail injector', 'Metered high-pressure nozzle that atomizes fuel into the piston bowl.', 'valve', vec(0, 1.42, 0.2)), part('high-pressure-pump', 'High-pressure pump', 'Fuel pump that maintains rail pressure for precise injection events.', 'rotating', vec(-0.85, 0.6, 0)), part('glow-plug', 'Glow plug', 'Electrical heater used for cold starting assistance.', 'electrical', vec(0.18, 1.35, 0.1)), ], guidedTour: tour([ { id: 'air-only-compression', title: 'Compress air first', body: 'Only air enters during the intake stroke, allowing much higher compression ratios before fuel arrives.', parts: ['intake-valve', 'piston-bowl'], }, { id: 'injection-plume', title: 'Fuel injection event', body: 'The injector atomizes fuel near top dead centre; ignition starts after a short delay as droplets mix with hot air.', parts: ['common-rail-injector', 'piston-bowl', 'high-pressure-pump'], preset: 'top', }, { id: 'torque-path', title: 'High torque structure', body: 'Large pressure rise demands a strong rod, crankshaft, block, and bearing support.', parts: ['connecting-rod', 'crankshaft', 'cylinder-block'], }, ]), related: ['four-stroke-petrol-engine', 'turbocharger', 'jet-engine-turbojet', 'hydraulic-cylinder'], animation: animation( 'dieselEngine', 'hybrid', 750, 250, 4500, 4, ['piston-bowl', 'crankshaft', 'connecting-rod', 'intake-valve', 'exhaust-valve', 'common-rail-injector'], [ 'Fuel spray opacity is phase-locked to late compression and early expansion.', 'Ignition heat bloom follows injection delay rather than spark timing.', ], 2, { injectionAdvance: { label: 'Injection advance', min: -10, max: 20, step: 1, default: 4, unit: '° BTDC', description: 'Crank angle before top dead centre for the main injection event.', }, }, ), asset: asset('diesel-engine', 3.4), learningObjectives: [ 'Distinguish compression ignition from spark ignition.', 'Connect compression ratio with air temperature rise.', 'Identify the injector and fuel pump path.', ], }), defineMachine({ id: 'v8-engine', title: 'V8 Engine', subtitle: 'Two banks of four cylinders with a shared crankshaft and firing-order timing.', category: 'engines', difficulty: 'advanced', complexity: 9, releaseOrder: 4, createdAt: '2025-01-04', thumbnail: categoryThumbnails.engines, tags: ['engine', 'v8', 'multi-cylinder', 'firing order'], keywords: ['v8', 'cross plane crank', 'firing order', 'cylinder bank', 'manifold'], description: 'A V8 engine packages eight cylinders into two angled banks driving one crankshaft. The registry entry is organized for bank isolation, firing-order highlighting, and crank phase visualization so the viewer can explain balance, torque overlap, and packaging.', facts: [ fact('Cylinder layout', '2 banks × 4 cylinders', 'The V angle is commonly 90 degrees for automotive V8s.'), fact('Typical speed', '600-7,000 rpm', 'Performance engines may exceed this range.'), fact('Common firing order', '1-8-4-3-6-5-7-2', 'One representative cross-plane sequence used for animation labels.'), fact('Primary advantage', 'Smooth high output', 'Overlapping power strokes improve torque delivery.'), fact('Common applications', 'Performance cars, trucks, marine drives'), ], parts: [ part('left-cylinder-bank', 'Left cylinder bank', 'Four-cylinder bank angled from the crankshaft centreline.', 'housing', vec(-0.7, 0.3, 0)), part('right-cylinder-bank', 'Right cylinder bank', 'Opposing four-cylinder bank sharing the same crankcase.', 'housing', vec(0.7, 0.3, 0)), part('cross-plane-crankshaft', 'Cross-plane crankshaft', 'Crankshaft with throws arranged for smooth V8 firing intervals.', 'rotating', vec(0, -0.55, 0)), part('piston-set', 'Piston set', 'Eight pistons phase-offset according to crank throw and bank angle.', 'reciprocating', vec(0, 0.85, 0.25)), part('camshaft-set', 'Camshaft set', 'Valve train shafts controlling intake and exhaust timing for both banks.', 'rotating', vec(0, 1.1, -0.35)), part('intake-manifold', 'Intake manifold', 'Central plenum distributing air to both cylinder banks.', 'housing', vec(0, 1.35, 0.2)), part('exhaust-headers', 'Exhaust headers', 'Tuned runners carrying exhaust pulses away from each bank.', 'fluid', vec(0, 0.55, 0.75)), part('timing-chain', 'Timing chain', 'Synchronizes camshaft rotation with crankshaft position.', 'rotating', vec(-0.95, 0.2, -0.2)), part('flywheel', 'Flywheel', 'Large inertia wheel coupled to the rear of the crankshaft.', 'rotating', vec(1.1, -0.45, 0)), ], guidedTour: tour([ { id: 'bank-layout', title: 'Two-bank packaging', body: 'The V layout shortens engine length while keeping eight cylinders connected to one crankshaft.', parts: ['left-cylinder-bank', 'right-cylinder-bank', 'cross-plane-crankshaft'], preset: 'front', }, { id: 'firing-order', title: 'Firing order pulse train', body: 'Cylinder highlights step through the firing order to show how torque pulses overlap.', parts: ['piston-set', 'cross-plane-crankshaft', 'exhaust-headers'], cue: 'firing-order', }, { id: 'timing-drive', title: 'Shared timing drive', body: 'The timing chain keeps camshaft events synchronized with crank angle across both banks.', parts: ['timing-chain', 'camshaft-set', 'cross-plane-crankshaft'], }, ]), related: ['four-stroke-petrol-engine', 'diesel-engine', 'turbocharger', 'manual-gearbox-5-speed'], animation: animation( 'v8Engine', 'hybrid', 850, 300, 7000, 8, ['cross-plane-crankshaft', 'piston-set', 'camshaft-set', 'timing-chain'], [ 'Cylinder fire highlights use a cross-plane firing-order table.', 'Left and right bank piston groups are instanced for performance.', ], 2, ), asset: asset('v8-engine', 4.4), learningObjectives: [ 'Explain how multiple cylinders smooth torque delivery.', 'Trace a representative V8 firing order.', 'Identify the timing drive and manifold functions.', ], }), defineMachine({ id: 'wankel-rotary-engine', title: 'Wankel Rotary Engine', subtitle: 'Eccentric triangular rotor sweeping chambers through intake, compression, combustion, and exhaust.', category: 'engines', difficulty: 'advanced', complexity: 8, releaseOrder: 5, createdAt: '2025-01-05', thumbnail: categoryThumbnails.engines, tags: ['engine', 'rotary', 'wankel', 'apex seal'], keywords: ['wankel', 'rotary engine', 'epitrochoid', 'apex seals', 'eccentric shaft'], description: 'The Wankel rotary engine uses a rounded triangular rotor orbiting in an epitrochoid housing. Its geometry creates three moving chambers, replacing pistons and connecting rods with an eccentric shaft and sealing challenges.', facts: [ fact('Rotor geometry', 'Reuleaux-like triangle', 'The rotor has convex flanks and three apex seals.'), fact('Output relation', '3 shaft rev / rotor rev', 'The eccentric shaft turns three times for one rotor revolution.'), fact('Strength', 'Compact smooth rotation', 'Few reciprocating masses make high-speed operation smooth.'), fact('Challenge', 'Seal wear and emissions', 'Apex sealing and chamber shape complicate combustion.'), fact('Common applications', 'Sports cars, UAVs, compact generators'), ], parts: [ part('epitrochoid-housing', 'Epitrochoid housing', 'Figure-eight-like chamber wall that defines rotor chamber volume.', 'housing', vec(-0.2, 0, 0)), part('triangular-rotor', 'Triangular rotor', 'Three-sided rotor that orbits eccentrically while sealing three chambers.', 'rotating', vec(0, 0.25, 0)), part('eccentric-shaft', 'Eccentric shaft', 'Output shaft with offset lobe driven by rotor orbit.', 'rotating', vec(0, -0.45, 0)), part('apex-seals', 'Apex seals', 'Spring-loaded seals at rotor tips maintaining chamber separation.', 'valve', vec(0.45, 0.55, 0.2)), part('intake-port', 'Intake port', 'Housing port uncovered by the moving chamber for fresh charge.', 'fluid', vec(-0.75, 0.15, 0.1)), part('exhaust-port', 'Exhaust port', 'Housing port where expanded gas leaves the chamber.', 'fluid', vec(0.75, -0.15, 0.1)), part('spark-plugs', 'Twin spark plugs', 'Ignition electrodes placed to burn the long chamber volume.', 'electrical', vec(0, 0.9, 0.1)), part('stationary-gear', 'Stationary gear', 'Fixed internal gear that constrains rotor orbital motion.', 'rotating', vec(0, -0.1, -0.35)), ], guidedTour: tour([ { id: 'orbiting-rotor', title: 'Orbit, not reciprocation', body: 'The rotor rotates and orbits at the same time, continuously changing chamber volumes.', parts: ['triangular-rotor', 'eccentric-shaft', 'stationary-gear'], }, { id: 'three-chambers', title: 'Three active chambers', body: 'Each rotor face participates in a different phase of the cycle as it passes ports and spark plugs.', parts: ['epitrochoid-housing', 'intake-port', 'exhaust-port', 'spark-plugs'], }, { id: 'sealing', title: 'Apex seal challenge', body: 'The apex seals must slide around the housing while withstanding heat, pressure, and lubrication limits.', parts: ['apex-seals', 'epitrochoid-housing'], }, ]), related: ['two-stroke-engine', 'jet-engine-turbojet', 'turbocharger'], animation: animation( 'wankelRotaryEngine', 'rotary', 1200, 400, 9000, 6, ['triangular-rotor', 'eccentric-shaft', 'apex-seals'], [ 'Rotor pose follows a 3:1 eccentric shaft relationship.', 'Chamber color bands indicate intake, compression, combustion, and exhaust volumes.', ], 3, ), asset: asset('wankel-rotary-engine', 3), learningObjectives: [ 'Describe how rotor orbit creates changing chamber volumes.', 'Explain the 3:1 eccentric shaft relationship.', 'Identify why apex seals are critical.', ], }), defineMachine({ id: 'steam-engine', title: 'Steam Engine', subtitle: 'Reciprocating external-combustion engine with slide valve, flywheel, and governor.', category: 'engines', difficulty: 'intermediate', complexity: 7, releaseOrder: 6, createdAt: '2025-01-06', thumbnail: categoryThumbnails.engines, tags: ['engine', 'steam', 'flywheel', 'governor'], keywords: ['steam engine', 'slide valve', 'flywheel', 'governor', 'crosshead'], description: 'A steam engine uses pressurized steam from an external boiler to push a piston. The viewer architecture separates valve timing, crosshead guidance, crank conversion, and flyball governor feedback so each historic mechanism can be explored independently.', facts: [ fact('Energy source', 'External combustion', 'Heat is generated outside the cylinder in a boiler.'), fact('Working fluid', 'Steam', 'Expanding steam drives the piston and is exhausted or condensed.'), fact('Historic era', '18th-19th century', 'Central to industrial power and rail transport.'), fact('Speed range', '50-400 rpm', 'Large engines often operate at modest rotational speed.'), fact('Common applications', 'Locomotives, mills, pumps, ships'), ], parts: [ part('steam-cylinder', 'Steam cylinder', 'Pressure vessel where steam expands against the piston.', 'housing', vec(-0.45, 0.2, 0)), part('piston-and-rod', 'Piston and rod', 'Reciprocating assembly pushed alternately by steam pressure.', 'reciprocating', vec(0.05, 0.35, 0)), part('slide-valve', 'Slide valve', 'Valve block that admits and exhausts steam on alternating sides of the piston.', 'valve', vec(-0.4, 0.72, 0.1)), part('valve-chest', 'Valve chest', 'Steam distribution chamber surrounding the slide valve.', 'housing', vec(-0.55, 0.85, 0)), part('crosshead', 'Crosshead', 'Guide block that keeps piston rod force aligned with the cylinder.', 'reciprocating', vec(0.35, 0.15, 0)), part('connecting-rod', 'Connecting rod', 'Long rod linking the crosshead to the crank pin.', 'reciprocating', vec(0.75, 0.05, 0)), part('flywheel', 'Flywheel', 'Large wheel storing energy between piston strokes.', 'rotating', vec(1.15, 0, 0)), part('centrifugal-governor', 'Centrifugal governor', 'Flyball speed regulator that throttles steam admission.', 'control', vec(0.75, 1.05, 0.15)), part('crank', 'Crank', 'Offset crank converting rod motion into flywheel rotation.', 'rotating', vec(0.95, 0.05, 0)), ], guidedTour: tour([ { id: 'steam-admission', title: 'Steam admission', body: 'The slide valve routes steam to one side of the piston while opening the other side to exhaust.', parts: ['slide-valve', 'valve-chest', 'steam-cylinder'], }, { id: 'straight-line-to-rotation', title: 'Guided reciprocation', body: 'The crosshead keeps the piston rod straight while the connecting rod swings through the crank arc.', parts: ['crosshead', 'connecting-rod', 'crank', 'flywheel'], preset: 'front', }, { id: 'governor-feedback', title: 'Mechanical speed control', body: 'As speed rises, governor balls move outward and can reduce throttle opening.', parts: ['centrifugal-governor', 'flywheel'], }, ]), related: ['slider-crank', 'scotch-yoke', 'centrifugal-pump'], animation: animation( 'steamEngine', 'hybrid', 120, 20, 500, 4, ['piston-and-rod', 'slide-valve', 'crosshead', 'connecting-rod', 'flywheel', 'centrifugal-governor', 'crank'], [ 'Valve lead is visualized as the slide valve moves slightly ahead of piston dead centre.', 'Governor ball radius responds to shaft speed with a damped spring model.', ], ), asset: asset('steam-engine', 4.1), learningObjectives: [ 'Trace steam admission and exhaust through the slide valve.', 'Identify how a crosshead protects the piston rod from side load.', 'Explain flywheel energy storage.', ], }), defineMachine({ id: 'jet-engine-turbojet', title: 'Jet Engine (Turbojet)', subtitle: 'Continuous-flow gas turbine with intake, compressor, combustor, turbine, and nozzle.', category: 'engines', difficulty: 'advanced', complexity: 9, releaseOrder: 7, createdAt: '2025-01-07', thumbnail: categoryThumbnails.engines, tags: ['engine', 'gas turbine', 'turbojet', 'compressor'], keywords: ['turbojet', 'gas turbine', 'compressor', 'combustor', 'turbine', 'nozzle'], description: 'A turbojet accelerates air continuously through compressor stages, combustion, turbine extraction, and a converging nozzle. The scaffold models it as axial modules so cross-sections, flow overlays, and staged compressor animations can be implemented without a monolithic scene.', facts: [ fact('Cycle', 'Brayton cycle', 'Compression, heat addition, expansion, and exhaust occur continuously.'), fact('Compressor type', 'Axial stages', 'Multiple rotor-stator pairs raise pressure gradually.'), fact('Turbine role', 'Drives compressor', 'The turbine extracts enough energy to power the compressor shaft.'), fact('Best use', 'High-speed flight', 'Pure turbojets are efficient at high aircraft speeds.'), fact('Common applications', 'Early jets, missiles, test rigs'), ], parts: [ part('inlet-cone', 'Inlet cone', 'Streamlined intake centrebody that conditions incoming air.', 'housing', vec(-1.1, 0, 0)), part('compressor-rotor', 'Compressor rotor stages', 'Alternating rotating blade rows that add kinetic energy to air.', 'rotating', vec(-0.55, 0, 0)), part('compressor-stators', 'Compressor stators', 'Stationary vanes that diffuse and redirect compressor flow.', 'housing', vec(-0.35, 0.45, 0)), part('combustor-cans', 'Combustor cans', 'Flame tubes where fuel burns in compressed air.', 'housing', vec(0.2, 0, 0)), part('fuel-injectors', 'Fuel injectors', 'Nozzles metering fuel into the primary combustion zone.', 'valve', vec(0.1, 0.55, 0.1)), part('turbine-rotor', 'Turbine rotor', 'Hot-section blade rows extracting work for the compressor.', 'rotating', vec(0.75, 0, 0)), part('main-shaft', 'Main shaft', 'Shaft connecting compressor and turbine rotors.', 'rotating', vec(0, -0.25, 0)), part('exhaust-nozzle', 'Exhaust nozzle', 'Converging outlet that converts pressure and heat into jet velocity.', 'fluid', vec(1.15, 0, 0)), ], guidedTour: tour([ { id: 'airflow-path', title: 'Continuous airflow path', body: 'Air enters the intake, is compressed, heated, expanded through the turbine, and accelerated through the nozzle.', parts: ['inlet-cone', 'compressor-rotor', 'combustor-cans', 'turbine-rotor', 'exhaust-nozzle'], preset: 'left', }, { id: 'compressor-staging', title: 'Rotor-stator pressure rise', body: 'Rotor blades add energy while stators recover pressure and reset flow angle for the next stage.', parts: ['compressor-rotor', 'compressor-stators'], }, { id: 'turbine-balance', title: 'Turbine power balance', body: 'The turbine extracts just enough work to keep the compressor spinning; remaining energy produces thrust.', parts: ['turbine-rotor', 'main-shaft', 'exhaust-nozzle'], }, ]), related: ['turbofan-engine', 'turbocharger', 'centrifugal-pump'], animation: animation( 'turbojetEngine', 'thermal', 9000, 1000, 18000, 5, ['compressor-rotor', 'fuel-injectors', 'turbine-rotor', 'main-shaft'], [ 'Compressor and turbine discs spin on one shaft with different blade count instancing.', 'Flow particles accelerate after the combustor and through the nozzle.', ], ), asset: asset('jet-engine-turbojet', 5), learningObjectives: [ 'Name the five major turbojet modules in flow order.', 'Explain why turbine and compressor are shaft-coupled.', 'Relate nozzle acceleration to thrust.', ], }), defineMachine({ id: 'turbofan-engine', title: 'Turbofan Engine', subtitle: 'High-bypass jet engine splitting flow between a large fan duct and hot core.', category: 'engines', difficulty: 'advanced', complexity: 10, releaseOrder: 8, createdAt: '2025-01-08', thumbnail: categoryThumbnails.engines, tags: ['engine', 'turbofan', 'bypass', 'gas turbine'], keywords: ['turbofan', 'bypass ratio', 'fan', 'core flow', 'low pressure turbine'], description: 'A turbofan adds a large front fan and bypass duct around a gas-turbine core. This model is structured to show the split between cool bypass thrust and hot core thrust, making bypass ratio and spool separation visible in the scene.', facts: [ fact('Bypass ratio', '2:1-12:1+', 'Modern airliner engines move much more air around the core than through it.'), fact('Primary thrust source', 'Fan bypass flow', 'High-bypass engines gain propulsive efficiency by accelerating more air less aggressively.'), fact('Spools', 'Two or three', 'Separate shafts allow fan and compressor sections to rotate at different speeds.'), fact('Typical fan speed', '1,000-4,000 rpm', 'Large fans rotate slower than high-pressure core stages.'), fact('Common applications', 'Commercial airliners, business jets, transports'), ], parts: [ part('fan-rotor', 'Fan rotor', 'Large low-pressure rotor accelerating bypass and core inlet air.', 'rotating', vec(-1.25, 0, 0)), part('bypass-duct', 'Bypass duct', 'Annular passage routing fan air around the hot core.', 'fluid', vec(-0.25, 0.8, 0)), part('core-compressor', 'Core compressor', 'High-pressure compressor raising pressure before combustion.', 'rotating', vec(-0.25, 0, 0)), part('annular-combustor', 'Annular combustor', 'Continuous ring combustor adding heat to core flow.', 'housing', vec(0.35, 0, 0)), part('high-pressure-turbine', 'High-pressure turbine', 'Hot turbine driving the core compressor spool.', 'rotating', vec(0.75, 0, 0)), part('low-pressure-turbine', 'Low-pressure turbine', 'Downstream turbine driving the fan and booster spool.', 'rotating', vec(1.05, 0, 0)), part('mixer-nozzle', 'Mixer and nozzle', 'Exit region where bypass and core streams leave the nacelle.', 'fluid', vec(1.35, 0, 0)), part('nacelle', 'Nacelle', 'Aerodynamic outer housing around the fan and bypass duct.', 'housing', vec(-0.1, 1.1, 0)), ], guidedTour: tour([ { id: 'flow-split', title: 'Bypass and core split', body: 'The fan sends most air through the bypass duct while a smaller stream enters the compressor core.', parts: ['fan-rotor', 'bypass-duct', 'core-compressor'], preset: 'left', }, { id: 'two-spool', title: 'Different shaft speeds', body: 'Low-pressure turbine stages drive the large fan while high-pressure turbine stages drive the compact core compressor.', parts: ['fan-rotor', 'high-pressure-turbine', 'low-pressure-turbine'], }, { id: 'propulsive-efficiency', title: 'Efficient thrust', body: 'Accelerating a large mass of bypass air modestly is efficient for subsonic aircraft.', parts: ['bypass-duct', 'mixer-nozzle'], }, ]), related: ['jet-engine-turbojet', 'turbocharger', 'centrifugal-pump'], animation: animation( 'turbofanEngine', 'thermal', 2500, 500, 6000, 6, ['fan-rotor', 'core-compressor', 'high-pressure-turbine', 'low-pressure-turbine'], [ 'Fan spool and high-pressure spool have independent RPM multipliers.', 'Bypass flow particles use cooler color and larger volume than core flow particles.', ], 1, { bypassRatio: { label: 'Bypass ratio', min: 2, max: 12, step: 0.5, default: 8, description: 'Mass-flow ratio between bypass stream and core stream.', }, }, ), asset: asset('turbofan-engine', 5.4), learningObjectives: [ 'Distinguish bypass flow from core flow.', 'Explain why turbofans can be more efficient than turbojets at subsonic speeds.', 'Identify low- and high-pressure turbine roles.', ], }), defineMachine({ id: 'planetary-gearbox', title: 'Planetary Gearbox', subtitle: 'Compact epicyclic gear train with sun, planets, carrier, and ring gear.', category: 'gearboxes', difficulty: 'intermediate', complexity: 8, releaseOrder: 9, createdAt: '2025-01-09', thumbnail: categoryThumbnails.gearboxes, tags: ['gearbox', 'epicyclic', 'gear ratio', 'planetary'], keywords: ['planetary gearbox', 'sun gear', 'planet gear', 'ring gear', 'carrier'], description: 'A planetary gearbox uses multiple planet gears meshing with a central sun gear and an internal ring gear. Different members can be held, driven, or used as output, enabling compact ratio changes and high torque density.', facts: [ fact('Members', 'Sun, planets, carrier, ring', 'Any member can be input, output, or held depending on the mode.'), fact('Torque density', 'High', 'Multiple planets share load around the pitch circle.'), fact('Typical ratios', '3:1-10:1 per stage', 'Compound stages can achieve much higher reduction.'), fact('Common applications', 'Automatic transmissions, robotics, wind turbines'), fact('Key concept', 'Relative motion', 'Gear speed is computed relative to the moving carrier.'), ], parts: [ part('sun-gear', 'Sun gear', 'Central external gear meshing with all planets.', 'rotating', vec(0, 0, 0.35)), part('planet-gears', 'Planet gears', 'Load-sharing gears orbiting the sun and meshing with the ring.', 'rotating', vec(0.55, 0, 0.2)), part('planet-carrier', 'Planet carrier', 'Armature holding planet pins and transmitting orbital motion.', 'rotating', vec(0, 0, -0.25)), part('ring-gear', 'Ring gear', 'Internal gear surrounding and meshing with planet gears.', 'housing', vec(0, 0, -0.5)), part('input-shaft', 'Input shaft', 'Selectable input member for ratio demonstrations.', 'rotating', vec(-0.9, 0, 0)), part('output-shaft', 'Output shaft', 'Selectable output member for ratio demonstrations.', 'rotating', vec(0.9, 0, 0)), part('brake-clutch-pack', 'Brake and clutch pack', 'Control element used to hold or couple gear members.', 'control', vec(0, -0.75, 0)), ], guidedTour: tour([ { id: 'epicyclic-layout', title: 'Epicyclic layout', body: 'Planets spin on their own pins while orbiting around the sun gear inside the ring.', parts: ['sun-gear', 'planet-gears', 'planet-carrier', 'ring-gear'], }, { id: 'selectable-members', title: 'Input, output, held member', body: 'Changing which member is held changes the direction and ratio without moving the gear set.', parts: ['input-shaft', 'output-shaft', 'brake-clutch-pack'], }, { id: 'load-sharing', title: 'Load sharing', body: 'Several planets split tooth load, allowing a compact gear train to transmit large torque.', parts: ['planet-gears', 'planet-carrier'], }, ]), related: ['differential-gear', 'manual-gearbox-5-speed', 'cvt', 'worm-gear-drive'], animation: animation( 'planetaryGearbox', 'rotary', 120, 5, 1500, 6, ['sun-gear', 'planet-gears', 'planet-carrier', 'ring-gear', 'input-shaft', 'output-shaft'], [ 'Relative angular velocities are derived from tooth counts and selected held member.', 'Planet meshes are suitable for instancing because geometry repeats around the carrier.', ], 1, { sunTeeth: { label: 'Sun teeth', min: 12, max: 48, step: 1, default: 24, description: 'Virtual tooth count used for ratio readout.', }, ringTeeth: { label: 'Ring teeth', min: 48, max: 120, step: 1, default: 72, description: 'Internal ring tooth count used for ratio readout.', }, }, ), asset: asset('planetary-gearbox', 3.1), learningObjectives: [ 'Identify the sun, planet, carrier, and ring members.', 'Explain how holding different members changes ratio.', 'Describe why load sharing improves torque density.', ], }), defineMachine({ id: 'differential-gear', title: 'Differential Gear', subtitle: 'Final-drive gear set allowing two axle shafts to rotate at different speeds.', category: 'gearboxes', difficulty: 'intermediate', complexity: 7, releaseOrder: 10, createdAt: '2025-01-10', thumbnail: categoryThumbnails.gearboxes, tags: ['gearbox', 'differential', 'vehicle driveline', 'bevel gears'], keywords: ['differential', 'spider gears', 'side gears', 'ring gear', 'cornering'], description: 'A differential gear splits torque between two axle shafts while allowing different wheel speeds during cornering. The model highlights the ring-and-pinion reduction, spider gear action, and straight-line versus cornering states.', facts: [ fact('Primary role', 'Speed difference', 'Inside and outside wheels travel different path lengths in a turn.'), fact('Gear type', 'Bevel spider gears', 'Small bevel gears distribute motion to side gears.'), fact('Straight-line state', 'Spider gears idle', 'The carrier and side gears rotate together with minimal spider spin.'), fact('Cornering state', 'Spider gears rotate', 'Relative wheel speed causes the spider gears to walk.'), fact('Common applications', 'Automotive axles, robotics drive modules'), ], parts: [ part('ring-gear', 'Ring gear', 'Large final-drive gear bolted to the differential carrier.', 'rotating', vec(0, 0.55, 0)), part('drive-pinion', 'Drive pinion', 'Small gear from driveshaft that turns the ring gear.', 'rotating', vec(-0.9, 0, 0)), part('differential-carrier', 'Differential carrier', 'Rotating cage that supports spider gear pins.', 'rotating', vec(0, 0, 0)), part('spider-gears', 'Spider gears', 'Small bevel gears that allow side gears to counter-rotate relatively.', 'rotating', vec(0, 0.25, 0.35)), part('left-side-gear', 'Left side gear', 'Bevel gear splined to the left axle shaft.', 'rotating', vec(-0.55, 0, 0)), part('right-side-gear', 'Right side gear', 'Bevel gear splined to the right axle shaft.', 'rotating', vec(0.55, 0, 0)), part('axle-shafts', 'Axle shafts', 'Output shafts carrying torque to left and right wheels.', 'rotating', vec(0, -0.55, 0)), part('casing', 'Differential casing', 'Housing supporting bearings and lubricant around the gear set.', 'housing', vec(0, 0, -0.6)), ], guidedTour: tour([ { id: 'final-drive', title: 'Final-drive reduction', body: 'The pinion drives the ring gear, reducing speed and increasing torque before the axle shafts.', parts: ['drive-pinion', 'ring-gear'], }, { id: 'straight-line', title: 'Straight-line motion', body: 'When both wheels need the same speed, the carrier and side gears rotate as a unit.', parts: ['differential-carrier', 'left-side-gear', 'right-side-gear'], }, { id: 'cornering', title: 'Cornering difference', body: 'Spider gears rotate on their pin to let one axle speed up while the other slows down.', parts: ['spider-gears', 'axle-shafts'], cue: 'cornering-mode', }, ]), related: ['planetary-gearbox', 'bevel-gear-set', 'v8-engine', 'manual-gearbox-5-speed'], animation: animation( 'differentialGear', 'rotary', 180, 5, 1200, 4, ['drive-pinion', 'ring-gear', 'differential-carrier', 'spider-gears', 'left-side-gear', 'right-side-gear', 'axle-shafts'], [ 'Cornering parameter offsets left and right axle speeds while conserving average carrier speed.', 'Spider gear spin is zero in straight-line mode and rises with wheel speed delta.', ], 1, { corneringAmount: { label: 'Cornering amount', min: -1, max: 1, step: 0.05, default: 0, description: 'Negative favors left wheel speed; positive favors right wheel speed.', }, }, ), asset: asset('differential-gear', 3.2), learningObjectives: [ 'Explain why vehicle axles need differential action.', 'Identify carrier, spider gears, and side gears.', 'Compare straight-line and cornering states.', ], }), defineMachine({ id: 'manual-gearbox-5-speed', title: 'Manual Gearbox (5-speed)', subtitle: 'Constant-mesh transmission with synchronizers, selector forks, layshaft, and reverse idler.', category: 'gearboxes', difficulty: 'advanced', complexity: 9, releaseOrder: 11, createdAt: '2025-01-11', thumbnail: categoryThumbnails.gearboxes, tags: ['gearbox', 'manual transmission', 'synchromesh', 'vehicle driveline'], keywords: ['manual gearbox', 'synchromesh', 'selector fork', 'layshaft', 'reverse idler'], description: 'A five-speed manual gearbox keeps gear pairs in constant mesh while synchronizer hubs lock selected ratios to the output shaft. The data model separates shafts, gear clusters, synchronizers, and shift rails so guided tours can explain engagement without hardcoding gearbox logic into the viewer.', facts: [ fact('Gear style', 'Constant mesh', 'Most gears remain meshed; dog teeth select which gear is locked.'), fact('Forward ratios', '5', 'Representative passenger-car architecture.'), fact('Reverse mechanism', 'Idler gear', 'An additional gear reverses output direction.'), fact('Key component', 'Synchronizer', 'Matches gear and shaft speed before engagement.'), fact('Common applications', 'Passenger cars, light trucks, motorsport training'), ], parts: [ part('input-shaft', 'Input shaft', 'Receives clutch torque from the engine flywheel.', 'rotating', vec(-1, 0.25, 0)), part('layshaft', 'Layshaft', 'Countershaft carrying fixed gears driven by the input gear.', 'rotating', vec(0, -0.45, 0)), part('output-shaft', 'Output shaft', 'Shaft that delivers selected gear ratio to the driveline.', 'rotating', vec(1, 0.25, 0)), part('constant-mesh-gears', 'Constant-mesh gear pairs', 'Multiple helical gear pairs always engaged with corresponding partners.', 'rotating', vec(0, 0.15, 0.35)), part('synchronizer-hubs', 'Synchronizer hubs', 'Dog-clutch hubs and cones that lock a selected gear to the output shaft.', 'control', vec(0.25, 0.55, 0)), part('selector-forks', 'Selector forks', 'Forks sliding synchronizer collars according to shifter input.', 'control', vec(0.25, 0.85, 0.15)), part('shift-rails', 'Shift rails', 'Guided rods translating gear lever movement into fork position.', 'control', vec(-0.25, 0.95, 0)), part('reverse-idler', 'Reverse idler', 'Intermediate gear inserted to reverse output rotation direction.', 'rotating', vec(0.8, -0.85, 0.2)), ], guidedTour: tour([ { id: 'power-path', title: 'Power path', body: 'Torque enters the input shaft, drives the layshaft, and returns through the selected gear to the output shaft.', parts: ['input-shaft', 'layshaft', 'output-shaft', 'constant-mesh-gears'], preset: 'front', }, { id: 'synchro-engagement', title: 'Synchronizer engagement', body: 'The synchronizer cone equalizes speed before dog teeth lock the selected gear.', parts: ['synchronizer-hubs', 'selector-forks', 'shift-rails'], }, { id: 'reverse', title: 'Reverse idler', body: 'The reverse idler adds one more mesh, flipping output direction.', parts: ['reverse-idler', 'layshaft', 'output-shaft'], }, ]), related: ['differential-gear', 'cvt', 'bevel-gear-set'], animation: animation( 'manualGearboxFiveSpeed', 'rotary', 600, 50, 6500, 7, ['input-shaft', 'layshaft', 'output-shaft', 'constant-mesh-gears', 'synchronizer-hubs', 'selector-forks', 'reverse-idler'], [ 'Selected ratio controls which output gear is locked and which gears freewheel.', 'Synchronizer collar translation uses eased travel with a neutral detent.', ], 1, { selectedGear: { label: 'Selected gear', min: -1, max: 5, step: 1, default: 1, description: '-1 is reverse, 0 is neutral, 1-5 are forward gears.', }, }, ), asset: asset('manual-gearbox-5-speed', 4.2), learningObjectives: [ 'Trace torque through input, layshaft, and output shaft.', 'Explain how synchronizers select gears in a constant-mesh transmission.', 'Describe why reverse needs an idler gear.', ], }), defineMachine({ id: 'cvt', title: 'CVT (Continuously Variable Transmission)', subtitle: 'Variable-diameter pulley transmission using a belt to provide smooth ratio changes.', category: 'gearboxes', difficulty: 'intermediate', complexity: 7, releaseOrder: 12, createdAt: '2025-01-12', thumbnail: categoryThumbnails.gearboxes, tags: ['gearbox', 'cvt', 'belt drive', 'variable ratio'], keywords: ['cvt', 'continuously variable transmission', 'belt', 'pulley', 'ratio'], description: 'A belt-and-pulley CVT changes effective pulley diameter instead of selecting fixed gear pairs. The model exposes pulley sheave spacing, belt pitch radius, hydraulic actuation, and live ratio readout.', facts: [ fact('Ratio type', 'Continuous', 'Effective pulley diameters vary smoothly instead of stepping between gears.'), fact('Main elements', 'Two variable pulleys and belt', 'One pulley closes as the other opens to conserve belt length.'), fact('Control method', 'Hydraulic or electromechanical', 'Actuators clamp and position pulley sheaves.'), fact('Strength', 'Smooth engine loading', 'Engine can remain near an efficient operating point.'), fact('Common applications', 'Scooters, compact cars, snowmobiles, industrial drives'), ], parts: [ part('drive-pulley', 'Drive pulley', 'Input variable pulley connected to the engine or motor.', 'rotating', vec(-0.85, 0, 0)), part('driven-pulley', 'Driven pulley', 'Output variable pulley connected to the final drive.', 'rotating', vec(0.85, 0, 0)), part('steel-belt', 'Steel belt', 'Segmented belt transmitting torque between pulley pitch radii.', 'rotating', vec(0, 0.2, 0.28)), part('movable-sheaves', 'Movable sheaves', 'Axially sliding cone faces that change effective pulley radius.', 'control', vec(0, 0.55, 0)), part('hydraulic-actuator', 'Hydraulic actuator', 'Pressure-controlled mechanism applying clamp force and ratio movement.', 'control', vec(0, -0.65, 0)), part('input-shaft', 'Input shaft', 'Rotating shaft supporting the drive pulley.', 'rotating', vec(-1.25, 0, 0)), part('output-shaft', 'Output shaft', 'Rotating shaft supporting the driven pulley.', 'rotating', vec(1.25, 0, 0)), part('ratio-indicator', 'Ratio indicator', 'Non-physical overlay showing current effective drive ratio.', 'sensor', vec(0, 0.95, 0)), ], guidedTour: tour([ { id: 'variable-diameter', title: 'Variable pitch diameter', body: 'Closing a pulley forces the belt outward, increasing its effective radius on that pulley.', parts: ['drive-pulley', 'driven-pulley', 'movable-sheaves', 'steel-belt'], }, { id: 'ratio-sweep', title: 'Smooth ratio sweep', body: 'As one pulley radius grows, the other shrinks, creating a continuous ratio change.', parts: ['ratio-indicator', 'drive-pulley', 'driven-pulley'], cue: 'ratio-sweep', }, { id: 'clamp-force', title: 'Clamp force', body: 'The actuator must apply enough normal force to transmit torque without belt slip.', parts: ['hydraulic-actuator', 'movable-sheaves', 'steel-belt'], }, ]), related: ['manual-gearbox-5-speed', 'planetary-gearbox', 'worm-gear-drive'], animation: animation( 'continuouslyVariableTransmission', 'rotary', 900, 100, 6000, 5, ['drive-pulley', 'driven-pulley', 'steel-belt', 'movable-sheaves', 'hydraulic-actuator'], [ 'Belt path is recalculated from pulley pitch radii while maintaining approximate belt length.', 'Output speed is derived from current radius ratio.', ], 1, { ratio: { label: 'Ratio', min: 0.4, max: 2.5, step: 0.05, default: 1, description: 'Effective input-to-output speed ratio.', }, }, ), asset: asset('cvt', 3.4), learningObjectives: [ 'Explain how pulley sheave spacing changes ratio.', 'Identify why one pulley opens as the other closes.', 'Relate belt radius to output speed.', ], }), defineMachine({ id: 'worm-gear-drive', title: 'Worm Gear Drive', subtitle: 'High-reduction right-angle drive using a screw-like worm and toothed wheel.', category: 'gearboxes', difficulty: 'intermediate', complexity: 6, releaseOrder: 13, createdAt: '2025-01-13', thumbnail: categoryThumbnails.gearboxes, tags: ['gearbox', 'worm gear', 'right angle', 'self locking'], keywords: ['worm gear', 'worm wheel', 'self locking', 'reduction ratio', 'lead angle'], description: 'A worm gear drive meshes a threaded worm with a worm wheel to produce large reductions in a compact right-angle layout. The model supports visualizing sliding contact, lead angle, reduction ratio, and self-locking behavior.', facts: [ fact('Axis angle', 'Usually 90°', 'The worm and wheel shafts are commonly perpendicular.'), fact('Reduction', 'High per stage', 'A single-start worm with 40 wheel teeth gives a 40:1 reduction.'), fact('Efficiency', 'Moderate to low', 'Sliding contact creates friction and heat.'), fact('Self-locking', 'Possible', 'Low lead angle and friction can prevent back-driving.'), fact('Common applications', 'Hoists, adjusters, conveyors, tuning mechanisms'), ], parts: [ part('worm-screw', 'Worm screw', 'Threaded input gear resembling a power screw.', 'rotating', vec(-0.45, 0, 0)), part('worm-wheel', 'Worm wheel', 'Toothed wheel driven by the worm thread.', 'rotating', vec(0.45, 0, 0)), part('input-shaft', 'Input shaft', 'Shaft carrying torque into the worm.', 'rotating', vec(-0.85, 0, 0)), part('output-shaft', 'Output shaft', 'Shaft connected to the worm wheel.', 'rotating', vec(0.85, 0, 0)), part('tapered-bearings', 'Tapered bearings', 'Bearings reacting axial and radial worm loads.', 'bearing', vec(-0.45, -0.45, 0)), part('housing', 'Gear housing', 'Rigid case holding shaft alignment and lubricant.', 'housing', vec(0, 0, -0.55)), part('self-lock-indicator', 'Self-locking indicator', 'Overlay showing whether output torque can back-drive the worm.', 'sensor', vec(0, 0.75, 0)), ], guidedTour: tour([ { id: 'sliding-mesh', title: 'Sliding gear mesh', body: 'Unlike spur gears, the worm thread slides along the wheel tooth, creating frictional losses.', parts: ['worm-screw', 'worm-wheel'], }, { id: 'large-reduction', title: 'Large reduction', body: 'One worm revolution advances the wheel by a small number of teeth, producing a high ratio.', parts: ['worm-screw', 'worm-wheel', 'output-shaft'], }, { id: 'self-lock', title: 'Self-locking', body: 'At low lead angle, friction can prevent the wheel from driving the worm backward.', parts: ['self-lock-indicator', 'worm-screw', 'worm-wheel'], }, ]), related: ['bevel-gear-set', 'planetary-gearbox', 'toggle-clamp'], animation: animation( 'wormGearDrive', 'rotary', 90, 1, 1200, 5, ['worm-screw', 'worm-wheel', 'input-shaft', 'output-shaft', 'self-lock-indicator'], [ 'Wheel angular speed is worm speed multiplied by starts divided by tooth count.', 'Back-drive mode fades the output torque arrow when self-locking conditions are met.', ], 1, { leadAngle: { label: 'Lead angle', min: 2, max: 35, step: 1, default: 8, unit: '°', description: 'Thread lead angle used for self-locking demonstration.', }, }, ), asset: asset('worm-gear-drive', 2.8), learningObjectives: [ 'Identify worm and wheel geometry.', 'Calculate why worm drives can produce high ratios.', 'Explain self-locking conditions qualitatively.', ], }), defineMachine({ id: 'bevel-gear-set', title: 'Bevel Gear Set', subtitle: 'Intersecting-shaft gear pair transferring rotation through a right angle.', category: 'gearboxes', difficulty: 'intermediate', complexity: 6, releaseOrder: 14, createdAt: '2025-01-14', thumbnail: categoryThumbnails.gearboxes, tags: ['gearbox', 'bevel gear', 'right angle drive', 'spiral bevel'], keywords: ['bevel gear', 'right angle', 'spiral bevel', 'tooth contact', 'gear mesh'], description: 'A bevel gear set transfers torque between intersecting shafts, often at 90 degrees. The scaffold includes contact patch, bearing, and shim metadata so future scenes can compare straight and spiral bevel behavior.', facts: [ fact('Shaft geometry', 'Intersecting axes', 'Most examples use a 90-degree shaft angle.'), fact('Tooth variants', 'Straight or spiral', 'Spiral bevel teeth run smoother and quieter at speed.'), fact('Ratio range', '1:1-6:1 typical', 'Final drives often use moderate reduction.'), fact('Critical setup', 'Contact pattern', 'Pinion depth and backlash control tooth load distribution.'), fact('Common applications', 'Differentials, angle drills, marine drives'), ], parts: [ part('driving-bevel-gear', 'Driving bevel gear', 'Input bevel gear mounted on the driving shaft.', 'rotating', vec(-0.45, 0, 0)), part('driven-bevel-gear', 'Driven bevel gear', 'Mating gear on the perpendicular output shaft.', 'rotating', vec(0.45, 0, 0)), part('input-shaft', 'Input shaft', 'Shaft carrying the driving bevel gear.', 'rotating', vec(-0.85, 0, 0)), part('output-shaft', 'Output shaft', 'Perpendicular shaft carrying the driven bevel gear.', 'rotating', vec(0.45, 0.65, 0)), part('bearing-pairs', 'Bearing pairs', 'Opposed bearings supporting thrust and radial loads.', 'bearing', vec(0, -0.55, 0)), part('housing', 'Gear housing', 'Case maintaining shaft intersection and lubricant volume.', 'housing', vec(0, 0, -0.55)), part('tooth-contact-patch', 'Tooth contact patch', 'Overlay showing the loaded contact region on the tooth face.', 'sensor', vec(0, 0.35, 0.35)), part('shim-pack', 'Shim pack', 'Adjustment stack used to set pinion depth and backlash.', 'fastener', vec(-0.9, -0.3, 0.1)), ], guidedTour: tour([ { id: 'right-angle-drive', title: 'Right-angle transfer', body: 'The pitch cones meet at one point, allowing torque transfer between intersecting axes.', parts: ['driving-bevel-gear', 'driven-bevel-gear', 'input-shaft', 'output-shaft'], }, { id: 'contact-patch', title: 'Tooth contact pattern', body: 'Correct setup centers the contact patch so load is shared across the tooth face.', parts: ['tooth-contact-patch', 'shim-pack'], }, { id: 'bearing-loads', title: 'Thrust reaction', body: 'Bevel gears create axial thrust that must be reacted by bearing pairs.', parts: ['bearing-pairs', 'housing'], }, ]), related: ['differential-gear', 'worm-gear-drive', 'rack-and-pinion'], animation: animation( 'bevelGearSet', 'rotary', 240, 5, 3000, 4, ['driving-bevel-gear', 'driven-bevel-gear', 'input-shaft', 'output-shaft', 'tooth-contact-patch'], [ 'Gear rotations are constrained by tooth-count ratio and intersecting shaft axes.', 'Contact patch can shift with backlash and shim parameters.', ], ), asset: asset('bevel-gear-set', 2.7), learningObjectives: [ 'Describe how bevel gears transfer motion across intersecting shafts.', 'Explain why tooth contact setup matters.', 'Identify thrust loads and bearing support.', ], }), defineMachine({ id: 'centrifugal-pump', title: 'Centrifugal Pump', subtitle: 'Rotodynamic pump using an impeller and volute to raise fluid pressure.', category: 'pumps', difficulty: 'beginner', complexity: 5, releaseOrder: 15, createdAt: '2025-01-15', thumbnail: categoryThumbnails.pumps, tags: ['pump', 'centrifugal', 'impeller', 'fluid'], keywords: ['centrifugal pump', 'impeller', 'volute', 'cavitation', 'diffuser'], description: 'A centrifugal pump accelerates liquid outward with a rotating impeller and converts velocity into pressure in the volute or diffuser. The model is prepared for fluid streamlines, cavitation warnings, and head-flow readouts.', facts: [ fact('Pump class', 'Rotodynamic', 'Energy is added continuously by a rotating impeller.'), fact('Flow direction', 'Axial inlet, radial outlet', 'Many designs draw fluid in at the eye and discharge tangentially.'), fact('Key risk', 'Cavitation', 'Low inlet pressure can create vapor bubbles that collapse destructively.'), fact('Typical speed', '1,450-3,600 rpm', 'Common speeds are tied to electric motor pole counts.'), fact('Common applications', 'Water supply, HVAC, process circulation'), ], parts: [ part('inlet-nozzle', 'Inlet nozzle', 'Suction inlet feeding liquid to the impeller eye.', 'fluid', vec(-0.85, 0, 0)), part('impeller', 'Impeller', 'Rotating vaned wheel that adds kinetic energy to the fluid.', 'rotating', vec(0, 0, 0.25)), part('volute-casing', 'Volute casing', 'Spiral casing that collects and slows fluid to raise pressure.', 'housing', vec(0, 0, -0.55)), part('diffuser-vanes', 'Diffuser vanes', 'Stationary vanes recovering pressure from impeller exit velocity.', 'housing', vec(0.35, 0.35, 0)), part('shaft-and-seal', 'Shaft and mechanical seal', 'Rotating shaft with seal preventing leakage at the casing.', 'rotating', vec(0, -0.55, 0)), part('outlet-nozzle', 'Outlet nozzle', 'Discharge outlet carrying pressurized flow from the volute.', 'fluid', vec(0.85, 0.35, 0)), part('cavitation-indicator', 'Cavitation indicator', 'Overlay that warns when suction pressure is too low.', 'sensor', vec(-0.45, 0.65, 0)), ], guidedTour: tour([ { id: 'inlet-to-eye', title: 'Fluid enters the eye', body: 'Liquid arrives axially at the impeller eye before being swept outward by the blades.', parts: ['inlet-nozzle', 'impeller'], }, { id: 'velocity-to-pressure', title: 'Velocity becomes pressure', body: 'The volute expands flow area, converting impeller exit velocity into static pressure.', parts: ['impeller', 'volute-casing', 'outlet-nozzle'], }, { id: 'cavitation', title: 'Cavitation risk', body: 'If inlet pressure drops below vapor pressure, bubbles form and collapse near blade surfaces.', parts: ['cavitation-indicator', 'inlet-nozzle', 'impeller'], }, ]), related: ['gear-pump', 'piston-pump', 'jet-engine-turbojet'], animation: animation( 'centrifugalPump', 'fluid', 1750, 300, 3600, 4, ['impeller', 'shaft-and-seal', 'cavitation-indicator'], [ 'Particle speed increases from eye to impeller tip and slows in the volute.', 'Cavitation indicator responds to NPSH margin parameter.', ], 1, { inletPressure: { label: 'Inlet pressure', min: 0.2, max: 3, step: 0.1, default: 1.2, unit: 'bar abs', description: 'Used to display cavitation margin.', }, }, ), asset: asset('centrifugal-pump', 3), learningObjectives: [ 'Trace flow from suction inlet to discharge outlet.', 'Explain how an impeller adds kinetic energy.', 'Recognize cavitation conditions.', ], }), defineMachine({ id: 'gear-pump', title: 'Gear Pump', subtitle: 'Positive-displacement pump moving fluid around meshing gear teeth.', category: 'pumps', difficulty: 'beginner', complexity: 5, releaseOrder: 16, createdAt: '2025-01-16', thumbnail: categoryThumbnails.pumps, tags: ['pump', 'gear pump', 'positive displacement', 'hydraulic'], keywords: ['gear pump', 'positive displacement', 'meshing gears', 'relief valve'], description: 'A gear pump traps fluid between gear teeth and housing, carrying it from inlet to outlet while the mesh prevents backflow. The model supports meshing rotation, trapped volume packets, pressure relief, and displacement-per-revolution readouts.', facts: [ fact('Pump class', 'Positive displacement', 'Each revolution moves a nearly fixed volume.'), fact('Flow path', 'Around outer gear teeth', 'Fluid does not pass through the meshing centre.'), fact('Pressure limit', 'Relief valve required', 'Blocked outlet pressure can rise rapidly.'), fact('Typical speed', '500-3,000 rpm', 'Hydraulic gear pumps are often motor-driven.'), fact('Common applications', 'Hydraulic power units, lubrication, fuel transfer'), ], parts: [ part('pump-housing', 'Pump housing', 'Close-clearance body surrounding both gears.', 'housing', vec(0, 0, -0.45)), part('drive-gear', 'Drive gear', 'Powered gear pulling fluid into expanding tooth spaces.', 'rotating', vec(-0.35, 0, 0.2)), part('idler-gear', 'Idler gear', 'Meshing gear rotating opposite the drive gear.', 'rotating', vec(0.35, 0, 0.2)), part('inlet-port', 'Inlet port', 'Low-pressure opening feeding fluid into the gear cavities.', 'fluid', vec(-0.85, -0.35, 0)), part('outlet-port', 'Outlet port', 'High-pressure opening where trapped fluid exits.', 'fluid', vec(0.85, 0.35, 0)), part('side-plates', 'Side plates', 'Wear plates sealing gear faces to reduce internal leakage.', 'housing', vec(0, 0.6, 0)), part('relief-valve', 'Relief valve', 'Bypass valve protecting the pump from overpressure.', 'valve', vec(0.75, 0.75, 0)), part('shaft-seal', 'Shaft seal', 'Seal preventing leakage along the drive shaft.', 'bearing', vec(-0.75, 0.15, 0)), ], guidedTour: tour([ { id: 'trapped-volume', title: 'Trapped tooth volumes', body: 'Fluid fills spaces between gear teeth and housing, then travels around the outside.', parts: ['drive-gear', 'idler-gear', 'pump-housing'], }, { id: 'no-centre-flow', title: 'Mesh blocks return flow', body: 'The meshing gear teeth close the centre path so fluid cannot simply flow backward.', parts: ['drive-gear', 'idler-gear', 'inlet-port', 'outlet-port'], }, { id: 'pressure-protection', title: 'Pressure protection', body: 'A relief valve opens if downstream pressure exceeds a safe set point.', parts: ['relief-valve', 'outlet-port'], }, ]), related: ['centrifugal-pump', 'piston-pump', 'hydraulic-cylinder'], animation: animation( 'gearPump', 'fluid', 900, 50, 3000, 5, ['drive-gear', 'idler-gear', 'relief-valve'], [ 'Gear rotations are exactly counter-rotated with equal tooth pitch.', 'Fluid packets follow outer housing arcs and pause near relief bypass when active.', ], 1, { reliefPressure: { label: 'Relief pressure', min: 20, max: 250, step: 5, default: 120, unit: 'bar', }, }, ), asset: asset('gear-pump', 2.8), learningObjectives: [ 'Explain positive displacement in terms of trapped volume.', 'Trace fluid around the outside of the gears.', 'Describe why relief valves are required.', ], }), defineMachine({ id: 'piston-pump', title: 'Piston Pump', subtitle: 'Reciprocating positive-displacement pump with inlet and outlet check valves.', category: 'pumps', difficulty: 'intermediate', complexity: 6, releaseOrder: 17, createdAt: '2025-01-17', thumbnail: categoryThumbnails.pumps, tags: ['pump', 'piston pump', 'check valve', 'reciprocating'], keywords: ['piston pump', 'plunger pump', 'check valve', 'suction stroke', 'discharge stroke'], description: 'A piston pump uses reciprocating piston volume to draw fluid through an inlet check valve and discharge it through an outlet check valve. The scene contract includes valve state, chamber volume, and pressure pulse data.', facts: [ fact('Pump class', 'Positive displacement', 'Displacement depends on bore, stroke, and speed.'), fact('Valve type', 'Check valves', 'One-way valves coordinate suction and discharge.'), fact('Flow character', 'Pulsating', 'Single-cylinder pumps create pressure ripple.'), fact('Pressure capability', 'High', 'Plunger pumps can reach very high pressures with small flow.'), fact('Common applications', 'Pressure washers, metering pumps, hydraulic test rigs'), ], parts: [ part('cylinder-barrel', 'Cylinder barrel', 'Pressure chamber containing the reciprocating plunger.', 'housing', vec(-0.35, 0, 0)), part('piston-plunger', 'Piston / plunger', 'Reciprocating displacement element changing chamber volume.', 'reciprocating', vec(0.15, 0, 0)), part('eccentric-crank', 'Eccentric crank', 'Rotary input converting shaft motion into piston stroke.', 'rotating', vec(0.75, -0.1, 0)), part('inlet-check-valve', 'Inlet check valve', 'One-way valve opening during suction stroke.', 'valve', vec(-0.75, -0.35, 0)), part('outlet-check-valve', 'Outlet check valve', 'One-way valve opening during discharge stroke.', 'valve', vec(-0.75, 0.35, 0)), part('suction-manifold', 'Suction manifold', 'Low-pressure passage feeding the inlet check valve.', 'fluid', vec(-1.1, -0.45, 0)), part('discharge-manifold', 'Discharge manifold', 'High-pressure passage collecting outlet flow.', 'fluid', vec(-1.1, 0.45, 0)), part('return-spring', 'Return spring', 'Spring used in some pump architectures to bias piston or valves.', 'control', vec(0.25, 0.45, 0)), ], guidedTour: tour([ { id: 'suction-stroke', title: 'Suction stroke', body: 'As chamber volume grows, pressure drops and the inlet check valve opens.', parts: ['piston-plunger', 'inlet-check-valve', 'suction-manifold'], }, { id: 'discharge-stroke', title: 'Discharge stroke', body: 'As the piston advances, the outlet check valve opens and fluid is forced into the discharge manifold.', parts: ['piston-plunger', 'outlet-check-valve', 'discharge-manifold'], }, { id: 'pulsation', title: 'Pressure ripple', body: 'A single piston creates pulses; multi-piston designs phase cylinders to smooth flow.', parts: ['eccentric-crank', 'piston-plunger'], }, ]), related: ['gear-pump', 'hydraulic-cylinder', 'slider-crank'], animation: animation( 'pistonPump', 'reciprocating', 240, 20, 1200, 4, ['piston-plunger', 'eccentric-crank', 'inlet-check-valve', 'outlet-check-valve'], [ 'Chamber volume is sinusoidal from crank geometry.', 'Check valves open from pressure differential with slight damping.', ], ), asset: asset('piston-pump', 2.9), learningObjectives: [ 'Identify suction and discharge strokes.', 'Explain check valve timing.', 'Relate piston stroke volume to pump displacement.', ], }), defineMachine({ id: 'hydraulic-cylinder', title: 'Hydraulic Cylinder', subtitle: 'Linear actuator converting hydraulic pressure into extension and retraction force.', category: 'pumps', difficulty: 'beginner', complexity: 5, releaseOrder: 18, createdAt: '2025-01-18', thumbnail: categoryThumbnails.pumps, tags: ['hydraulic', 'actuator', 'cylinder', 'fluid power'], keywords: ['hydraulic cylinder', 'piston', 'rod', 'seal', 'pressure', 'actuator'], description: 'A hydraulic cylinder uses pressure acting over piston area to create linear force. The model includes rod-side and cap-side chambers, seals, ports, and a pressure indicator so learners can understand extension, retraction, and force difference.', facts: [ fact('Force equation', 'F = P × A', 'Output force equals pressure times effective piston area.'), fact('Retraction force', 'Lower than extension', 'The rod reduces effective area on the rod side.'), fact('Motion type', 'Linear actuator', 'Hydraulic cylinders produce direct linear movement.'), fact('Seal role', 'Leakage control', 'Dynamic seals separate pressure chambers and exclude contamination.'), fact('Common applications', 'Excavators, presses, brakes, industrial automation'), ], parts: [ part('cylinder-barrel', 'Cylinder barrel', 'Honed tube containing the piston and fluid chambers.', 'housing', vec(-0.35, 0, 0)), part('piston', 'Piston', 'Internal sliding disk separating cap and rod side chambers.', 'reciprocating', vec(0.1, 0, 0)), part('chrome-rod', 'Chrome rod', 'Polished rod transmitting linear force outside the cylinder.', 'reciprocating', vec(0.85, 0, 0)), part('gland-seal', 'Gland seal', 'Seal assembly around the rod at the cylinder head.', 'bearing', vec(0.45, 0.35, 0)), part('rod-wiper', 'Rod wiper', 'External seal scraping contaminants from the retracting rod.', 'bearing', vec(0.65, 0.4, 0)), part('base-port', 'Base port', 'Cap-side hydraulic port used for extension pressure.', 'fluid', vec(-0.75, 0.35, 0)), part('rod-port', 'Rod port', 'Rod-side hydraulic port used for retraction pressure.', 'fluid', vec(0.35, -0.35, 0)), part('end-caps', 'End caps', 'Structural closures retaining pressure and mounting loads.', 'housing', vec(0, -0.55, 0)), part('pressure-indicator', 'Pressure indicator', 'Overlay showing active chamber pressure and force output.', 'sensor', vec(0, 0.8, 0)), ], guidedTour: tour([ { id: 'extension', title: 'Extension chamber', body: 'Pressure at the base port acts on the full piston area and extends the rod.', parts: ['base-port', 'piston', 'chrome-rod'], }, { id: 'retraction', title: 'Retraction chamber', body: 'Pressure at the rod port acts on the annular area, so retraction force is lower at equal pressure.', parts: ['rod-port', 'piston', 'chrome-rod'], }, { id: 'sealing', title: 'Seals and contamination', body: 'The gland seal and wiper keep oil in and contaminants out during rod motion.', parts: ['gland-seal', 'rod-wiper'], }, ]), related: ['piston-pump', 'disc-brake-caliper', 'toggle-clamp'], animation: animation( 'hydraulicCylinder', 'reciprocating', 60, 1, 240, 4, ['piston', 'chrome-rod', 'pressure-indicator'], [ 'Rod position follows commanded valve state with eased acceleration at stroke ends.', 'Force readout computes cap-side and rod-side effective areas.', ], 1, { pressure: { label: 'Pressure', min: 0, max: 250, step: 5, default: 120, unit: 'bar', }, }, ), asset: asset('hydraulic-cylinder', 3.1), learningObjectives: [ 'Apply force equals pressure times area.', 'Explain why retraction force differs from extension force.', 'Identify rod seals and ports.', ], }), defineMachine({ id: 'scotch-yoke', title: 'Scotch Yoke', subtitle: 'Crank mechanism converting rotation into exact sinusoidal linear motion.', category: 'mechanisms', difficulty: 'beginner', complexity: 4, releaseOrder: 19, createdAt: '2025-01-19', thumbnail: categoryThumbnails.mechanisms, tags: ['mechanism', 'scotch yoke', 'linear motion', 'crank'], keywords: ['scotch yoke', 'crank pin', 'slotted yoke', 'sinusoidal motion'], description: 'A Scotch yoke uses a crank pin sliding in a slot to convert rotation into reciprocating motion. It produces simple harmonic displacement but introduces sliding contact and side loads at the slot.', facts: [ fact('Motion output', 'Sinusoidal displacement', 'Slider position is directly proportional to crank pin horizontal projection.'), fact('Stroke', '2 × crank radius', 'The yoke travels twice the crank throw.'), fact('Contact type', 'Sliding slot', 'The crank pin slides along the yoke slot.'), fact('Strength', 'Compact conversion', 'Few links create linear motion from rotation.'), fact('Common applications', 'Valve actuators, small pumps, demonstration mechanisms'), ], parts: [ part('crank-disk', 'Crank disk', 'Rotating disk carrying the offset crank pin.', 'rotating', vec(-0.55, 0, 0)), part('crank-pin', 'Crank pin', 'Offset pin that slides inside the yoke slot.', 'rotating', vec(-0.25, 0.25, 0.25)), part('slotted-yoke', 'Slotted yoke', 'Linear member with slot constrained by the crank pin.', 'reciprocating', vec(0.25, 0, 0)), part('linear-guides', 'Linear guides', 'Rails constraining the yoke to one axis of translation.', 'housing', vec(0.25, -0.45, 0)), part('output-rod', 'Output rod', 'Rod connected to the yoke to deliver reciprocating motion.', 'reciprocating', vec(0.85, 0, 0)), part('flywheel', 'Flywheel', 'Optional inertia disk smoothing input rotation.', 'rotating', vec(-0.9, 0, 0)), part('bearing-blocks', 'Bearing blocks', 'Supports maintaining crank shaft alignment.', 'bearing', vec(-0.55, -0.55, 0)), ], guidedTour: tour([ { id: 'pin-in-slot', title: 'Pin in slot', body: 'The crank pin rotates but is forced to slide vertically inside the yoke slot.', parts: ['crank-disk', 'crank-pin', 'slotted-yoke'], }, { id: 'sinusoidal-output', title: 'Sinusoidal output', body: 'The yoke displacement follows the horizontal projection of the crank radius.', parts: ['slotted-yoke', 'output-rod', 'linear-guides'], }, { id: 'sliding-wear', title: 'Sliding wear', body: 'The simple layout comes with sliding contact between pin and slot.', parts: ['crank-pin', 'slotted-yoke'], }, ]), related: ['slider-crank', 'geneva-drive', 'steam-engine'], animation: animation( 'scotchYoke', 'reciprocating', 90, 1, 900, 4, ['crank-disk', 'crank-pin', 'slotted-yoke', 'output-rod', 'flywheel'], [ 'Yoke translation equals crank radius multiplied by cosine of crank angle.', 'Crank pin local slot position is shown to reveal sliding contact.', ], ), asset: asset('scotch-yoke', 2.5), learningObjectives: [ 'Convert crank angle into yoke displacement.', 'Compare Scotch yoke and slider-crank motion.', 'Identify the sliding contact pair.', ], }), defineMachine({ id: 'geneva-drive', title: 'Geneva Drive', subtitle: 'Intermittent indexing mechanism with dwell periods between driven steps.', category: 'mechanisms', difficulty: 'intermediate', complexity: 6, releaseOrder: 20, createdAt: '2025-01-20', thumbnail: categoryThumbnails.mechanisms, tags: ['mechanism', 'geneva drive', 'intermittent motion', 'indexing'], keywords: ['geneva drive', 'indexing', 'dwell', 'drive pin', 'slots'], description: 'A Geneva drive converts continuous rotation into intermittent output rotation. The drive pin enters a slot to index the Geneva wheel, while locking surfaces hold the output stationary during dwell.', facts: [ fact('Output type', 'Intermittent rotation', 'The driven wheel advances in discrete angular steps.'), fact('Dwell', 'Built in', 'Locking geometry holds the output between indexing events.'), fact('Index angle', '360° / slots', 'A four-slot Geneva advances 90 degrees per index.'), fact('Motion concern', 'Impact and acceleration', 'Pin engagement creates high acceleration if not designed carefully.'), fact('Common applications', 'Film projectors, indexing tables, packaging equipment'), ], parts: [ part('drive-wheel', 'Drive wheel', 'Continuously rotating input disk.', 'rotating', vec(-0.55, 0, 0)), part('drive-pin', 'Drive pin', 'Pin that enters Geneva slots to index the output wheel.', 'rotating', vec(-0.25, 0.25, 0.2)), part('locking-disk', 'Locking disk', 'Circular surface preventing output rotation during dwell.', 'control', vec(-0.55, -0.35, 0)), part('geneva-wheel', 'Geneva wheel', 'Driven wheel with radial slots for intermittent indexing.', 'rotating', vec(0.55, 0, 0)), part('radial-slots', 'Radial slots', 'Slots receiving the drive pin during indexing.', 'housing', vec(0.55, 0.45, 0.1)), part('output-shaft', 'Output shaft', 'Shaft advanced step-by-step by the Geneva wheel.', 'rotating', vec(0.95, 0, 0)), part('dwell-sector', 'Dwell sector', 'Overlay showing the angular range where output remains stationary.', 'sensor', vec(0, 0.85, 0)), part('frame', 'Frame', 'Base plate supporting the drive and output shafts.', 'housing', vec(0, -0.55, 0)), ], guidedTour: tour([ { id: 'continuous-to-index', title: 'Continuous input, indexed output', body: 'The drive wheel turns steadily while the Geneva wheel advances only when the pin enters a slot.', parts: ['drive-wheel', 'drive-pin', 'geneva-wheel'], }, { id: 'dwell-period', title: 'Dwell period', body: 'Between indexing events, locking surfaces hold the output shaft stationary.', parts: ['locking-disk', 'dwell-sector', 'output-shaft'], }, { id: 'slot-count', title: 'Slot count sets step angle', body: 'A wheel with more slots creates smaller output steps.', parts: ['radial-slots', 'geneva-wheel'], }, ]), related: ['scotch-yoke', 'cam-and-follower', 'rack-and-pinion'], animation: animation( 'genevaDrive', 'intermittent', 60, 1, 600, 4, ['drive-wheel', 'drive-pin', 'locking-disk', 'geneva-wheel', 'output-shaft'], [ 'Output angle remains constant during dwell and advances during pin engagement.', 'Dwell sector overlay is computed from slot count.', ], 1, { slotCount: { label: 'Slot count', min: 3, max: 8, step: 1, default: 4, }, }, ), asset: asset('geneva-drive', 2.6), learningObjectives: [ 'Explain intermittent motion and dwell.', 'Relate slot count to index angle.', 'Identify pin engagement timing.', ], }), defineMachine({ id: 'cam-and-follower', title: 'Cam and Follower', subtitle: 'Profile-driven mechanism translating cam shape into programmed follower motion.', category: 'mechanisms', difficulty: 'intermediate', complexity: 6, releaseOrder: 21, createdAt: '2025-01-21', thumbnail: categoryThumbnails.mechanisms, tags: ['mechanism', 'cam', 'follower', 'motion profile'], keywords: ['cam and follower', 'eccentric cam', 'heart cam', 'snail cam', 'roller follower'], description: 'A cam and follower uses a rotating profile to impose a programmed displacement on a follower. The registry supports selectable eccentric, heart, and snail profiles with lift, dwell, and return behavior.', facts: [ fact('Input', 'Rotating cam', 'Cam angle determines follower displacement.'), fact('Follower type', 'Roller follower', 'A roller reduces sliding friction against the cam surface.'), fact('Profiles', 'Eccentric, heart, snail', 'Different profiles create different lift laws and dwell behavior.'), fact('Common use', 'Valve timing', 'Cams are widely used to actuate engine valves.'), fact('Design concern', 'Acceleration and jerk', 'Aggressive profiles can create vibration and contact loss.'), ], parts: [ part('camshaft', 'Camshaft', 'Input shaft carrying the cam profile.', 'rotating', vec(-0.55, 0, 0)), part('cam-profile', 'Cam profile', 'Shaped lobe defining the follower displacement curve.', 'rotating', vec(0, 0, 0.2)), part('roller-follower', 'Roller follower', 'Rolling contact element riding on the cam profile.', 'reciprocating', vec(0, 0.55, 0.2)), part('follower-stem', 'Follower stem', 'Guided linear member moved by the roller.', 'reciprocating', vec(0, 0.9, 0)), part('return-spring', 'Return spring', 'Spring maintaining contact between follower and cam.', 'control', vec(0.35, 0.75, 0)), part('guide-block', 'Guide block', 'Linear guide constraining follower motion.', 'housing', vec(-0.35, 0.75, 0)), part('profile-selector', 'Profile selector', 'Overlay for switching between cam lift profiles.', 'sensor', vec(0.75, 0.2, 0)), ], guidedTour: tour([ { id: 'profile-controls-motion', title: 'Shape controls motion', body: 'The cam radius at each angle sets the follower lift.', parts: ['cam-profile', 'roller-follower', 'follower-stem'], }, { id: 'spring-return', title: 'Contact maintenance', body: 'The spring keeps the follower pressed against the cam during return.', parts: ['return-spring', 'roller-follower'], }, { id: 'profile-comparison', title: 'Profile comparison', body: 'Switch profiles to compare smooth eccentric lift, heart-cam constant velocity, and snail-cam sudden drop.', parts: ['profile-selector', 'cam-profile'], cue: 'profile-sweep', }, ]), related: ['geneva-drive', 'slider-crank', 'toggle-clamp'], animation: animation( 'camAndFollower', 'reciprocating', 120, 1, 3000, 5, ['camshaft', 'cam-profile', 'roller-follower', 'follower-stem', 'profile-selector'], [ 'Follower lift is sampled from a normalized profile function.', 'Contact loss warning appears if acceleration exceeds spring capability parameter.', ], 1, { profile: { label: 'Profile', min: 0, max: 2, step: 1, default: 0, description: '0 eccentric, 1 heart, 2 snail.', }, }, ), asset: asset('cam-and-follower', 2.6), learningObjectives: [ 'Relate cam shape to follower displacement.', 'Compare common cam profiles.', 'Explain why spring force and acceleration matter.', ], }), defineMachine({ id: 'rack-and-pinion', title: 'Rack and Pinion', subtitle: 'Gear pair converting rotary motion into linear motion and back.', category: 'mechanisms', difficulty: 'beginner', complexity: 4, releaseOrder: 22, createdAt: '2025-01-22', thumbnail: categoryThumbnails.mechanisms, tags: ['mechanism', 'gear', 'linear motion', 'rack and pinion'], keywords: ['rack and pinion', 'linear motion', 'pinion', 'backlash', 'steering'], description: 'A rack and pinion converts rotation of a round gear into translation of a straight toothed rack. The model includes guide rails, backlash adjustment, and a position scale for learning displacement per revolution.', facts: [ fact('Conversion', 'Rotary ↔ linear', 'Either member can be input depending on application.'), fact('Travel per revolution', 'π × pitch diameter', 'One pinion revolution moves the rack by the pinion pitch circumference.'), fact('Backlash', 'Adjustable clearance', 'Too much clearance creates lost motion; too little increases friction.'), fact('Common applications', 'Steering racks, CNC axes, gates, actuators'), fact('Advantage', 'Simple direct motion', 'The mechanism is compact and easy to understand.'), ], parts: [ part('pinion', 'Pinion', 'Round gear that meshes with the straight rack.', 'rotating', vec(0, 0.35, 0.2)), part('rack', 'Rack', 'Straight toothed bar translating along guide rails.', 'reciprocating', vec(0, -0.2, 0.2)), part('linear-guide', 'Linear guide', 'Guideway constraining rack translation.', 'housing', vec(0, -0.55, 0)), part('bearing-blocks', 'Bearing blocks', 'Supports locating the pinion shaft.', 'bearing', vec(0, 0.75, 0)), part('housing', 'Housing', 'Frame maintaining gear mesh alignment.', 'housing', vec(0, 0, -0.45)), part('backlash-adjuster', 'Backlash adjuster', 'Spring or eccentric support setting mesh clearance.', 'control', vec(0.65, 0.2, 0)), part('position-scale', 'Position scale', 'Overlay measuring rack displacement.', 'sensor', vec(0, -0.85, 0)), ], guidedTour: tour([ { id: 'rotation-to-translation', title: 'Rotation to translation', body: 'The pinion teeth push the rack teeth, creating straight-line motion.', parts: ['pinion', 'rack'], }, { id: 'travel-math', title: 'Travel per revolution', body: 'Rack travel for one pinion revolution equals the pinion pitch circumference.', parts: ['pinion', 'position-scale', 'rack'], }, { id: 'backlash', title: 'Backlash adjustment', body: 'The adjuster controls mesh clearance to balance smoothness and lost motion.', parts: ['backlash-adjuster', 'pinion', 'rack'], }, ]), related: ['cam-and-follower', 'bevel-gear-set', 'worm-gear-drive'], animation: animation( 'rackAndPinion', 'reciprocating', 120, 1, 2000, 4, ['pinion', 'rack', 'position-scale'], [ 'Rack translation is pinion radius multiplied by angular displacement.', 'Backlash mode adds a deadband before rack motion reverses.', ], 1, { backlash: { label: 'Backlash', min: 0, max: 3, step: 0.1, default: 0.4, unit: 'mm', }, }, ), asset: asset('rack-and-pinion', 2.5), learningObjectives: [ 'Calculate rack travel from pinion rotation.', 'Identify backlash and guide components.', 'Explain reversible rotary-linear conversion.', ], }), defineMachine({ id: 'slider-crank', title: 'Slider Crank', subtitle: 'Foundational linkage converting crank rotation and slider reciprocation.', category: 'mechanisms', difficulty: 'beginner', complexity: 5, releaseOrder: 23, createdAt: '2025-01-23', thumbnail: categoryThumbnails.mechanisms, tags: ['mechanism', 'slider crank', 'linkage', 'dead centre'], keywords: ['slider crank', 'connecting rod', 'dead centre', 'crank', 'reciprocating'], description: 'A slider-crank linkage is the geometric core of many piston engines and reciprocating machines. It converts rotation into slider motion while introducing non-sinusoidal displacement caused by finite connecting rod length.', facts: [ fact('Members', 'Crank, rod, slider, ground', 'The classic four-link slider-crank mechanism.'), fact('Dead centres', 'TDC and BDC', 'Crank and rod align at the stroke extremes.'), fact('Stroke', '2 × crank radius', 'Slider travel is twice the crank throw.'), fact('Motion nuance', 'Rod-length effect', 'Finite rod length makes piston motion slightly asymmetric.'), fact('Common applications', 'Engines, compressors, pumps'), ], parts: [ part('crank', 'Crank', 'Rotating link with offset crank pin.', 'rotating', vec(-0.55, 0, 0)), part('connecting-rod', 'Connecting rod', 'Link between crank pin and slider wrist pin.', 'reciprocating', vec(0.05, 0.1, 0.2)), part('slider', 'Slider', 'Linear block or piston constrained to the guide.', 'reciprocating', vec(0.75, 0, 0)), part('linear-guide', 'Linear guide', 'Grounded guide forcing slider motion along one axis.', 'housing', vec(0.75, -0.45, 0)), part('crankshaft', 'Crankshaft', 'Input shaft carrying the crank throw.', 'rotating', vec(-0.85, 0, 0)), part('dead-centre-markers', 'Dead-centre markers', 'Overlays marking top and bottom dead centre positions.', 'sensor', vec(0.25, 0.6, 0)), part('flywheel', 'Flywheel', 'Inertia wheel smoothing crank rotation through dead centres.', 'rotating', vec(-1.15, 0, 0)), ], guidedTour: tour([ { id: 'four-members', title: 'Four-link mechanism', body: 'The crank rotates, the connecting rod swings, and the slider is constrained to a straight path.', parts: ['crank', 'connecting-rod', 'slider', 'linear-guide'], }, { id: 'dead-centres', title: 'Dead centres', body: 'At stroke extremes the crank and rod align, creating top and bottom dead centre positions.', parts: ['dead-centre-markers', 'crank', 'connecting-rod'], }, { id: 'rod-length', title: 'Connecting rod geometry', body: 'A shorter connecting rod increases side thrust and makes slider motion less sinusoidal.', parts: ['connecting-rod', 'slider', 'linear-guide'], }, ]), related: ['four-stroke-petrol-engine', 'steam-engine', 'scotch-yoke'], animation: animation( 'sliderCrank', 'reciprocating', 120, 1, 3000, 4, ['crank', 'connecting-rod', 'slider', 'crankshaft', 'flywheel'], [ 'Slider position is solved from crank radius and connecting-rod length.', 'Dead-centre markers pulse when crank angle approaches alignment.', ], 1, { rodRatio: { label: 'Rod ratio', min: 2, max: 5, step: 0.1, default: 3.5, description: 'Connecting rod length divided by crank radius.', }, }, ), asset: asset('slider-crank', 2.6), learningObjectives: [ 'Identify crank, rod, slider, and ground link.', 'Locate top and bottom dead centre.', 'Explain connecting rod length effects.', ], }), defineMachine({ id: 'toggle-clamp', title: 'Toggle Clamp', subtitle: 'Over-centre linkage creating high clamping force and stable lock.', category: 'mechanisms', difficulty: 'intermediate', complexity: 5, releaseOrder: 24, createdAt: '2025-01-24', thumbnail: categoryThumbnails.mechanisms, tags: ['mechanism', 'toggle clamp', 'linkage', 'mechanical advantage'], keywords: ['toggle clamp', 'over centre', 'mechanical advantage', 'linkage'], description: 'A toggle clamp uses linked levers that pass slightly over centre to lock a clamping arm. Its mechanical advantage rises rapidly near the toggle position, producing high holding force from modest handle input.', facts: [ fact('Principle', 'Over-centre lock', 'The linkage passes beyond alignment so load tends to keep it closed.'), fact('Mechanical advantage', 'Rises near toggle', 'Small handle motion can create large clamping force near lock.'), fact('Release', 'Reverse handle motion', 'Moving back across centre unlocks the linkage.'), fact('Common applications', 'Fixtures, jigs, woodworking, welding clamps'), fact('Design concern', 'Link stress', 'High force near lock increases pin and link load.'), ], parts: [ part('handle', 'Handle', 'User input lever rotating the toggle linkage.', 'control', vec(-0.75, 0.35, 0)), part('front-toggle-link', 'Front toggle link', 'Link transferring handle motion toward the clamp arm.', 'control', vec(-0.25, 0.2, 0.15)), part('rear-toggle-link', 'Rear toggle link', 'Secondary link forming the over-centre geometry.', 'control', vec(0.15, 0.1, 0.15)), part('pivot-pins', 'Pivot pins', 'Pinned joints allowing linkage rotation and carrying shear load.', 'fastener', vec(0, 0.45, 0.25)), part('clamp-arm', 'Clamp arm', 'Lever pressing the spindle pad onto the workpiece.', 'control', vec(0.55, 0.15, 0)), part('spindle-pad', 'Spindle pad', 'Adjustable contact pad applying clamping force.', 'control', vec(0.85, -0.25, 0)), part('base', 'Base', 'Mounting plate fixed to the fixture.', 'housing', vec(0, -0.55, 0)), part('over-centre-stop', 'Over-centre stop', 'Stop surface limiting travel beyond the toggle line.', 'sensor', vec(0.35, 0.55, 0)), ], guidedTour: tour([ { id: 'linkage-path', title: 'Lever linkage', body: 'Handle rotation moves two toggle links and drives the clamp arm downward.', parts: ['handle', 'front-toggle-link', 'rear-toggle-link', 'clamp-arm'], }, { id: 'mechanical-advantage', title: 'Mechanical advantage', body: 'As links approach alignment, output force rises sharply for a small handle movement.', parts: ['front-toggle-link', 'rear-toggle-link', 'spindle-pad'], }, { id: 'over-centre-lock', title: 'Over-centre lock', body: 'The linkage passes slightly beyond centre, so clamp load keeps the mechanism closed.', parts: ['over-centre-stop', 'pivot-pins', 'clamp-arm'], }, ]), related: ['hydraulic-cylinder', 'cam-and-follower', 'worm-gear-drive'], animation: animation( 'toggleClamp', 'reciprocating', 30, 1, 180, 5, ['handle', 'front-toggle-link', 'rear-toggle-link', 'clamp-arm', 'spindle-pad'], [ 'Link positions are solved as a planar four-bar approximation.', 'Mechanical advantage readout tends toward a high value near centre but is clamped for display.', ], 1, { handleAngle: { label: 'Handle angle', min: 0, max: 100, step: 1, default: 75, unit: '°', }, }, ), asset: asset('toggle-clamp', 2.5), learningObjectives: [ 'Explain over-centre locking.', 'Relate linkage geometry to mechanical advantage.', 'Identify pin load paths.', ], }), defineMachine({ id: 'ball-bearing', title: 'Ball Bearing', subtitle: 'Rolling-element bearing with inner race, outer race, balls, cage, and load distribution.', category: 'structural', difficulty: 'beginner', complexity: 4, releaseOrder: 25, createdAt: '2025-01-25', thumbnail: categoryThumbnails.structural, tags: ['bearing', 'rolling element', 'structural', 'machine element'], keywords: ['ball bearing', 'inner race', 'outer race', 'cage', 'load distribution'], description: 'A ball bearing reduces friction by separating inner and outer races with rolling balls. The model supports race rotation, cage speed, load vector overlays, and contact zone highlighting.', facts: [ fact('Contact type', 'Point contact', 'Balls contact races over small elliptical regions.'), fact('Friction', 'Low rolling friction', 'Rolling contact reduces friction compared with sliding bushings.'), fact('Cage role', 'Ball spacing', 'The cage prevents balls from rubbing directly together.'), fact('Load types', 'Radial and limited axial', 'Deep-groove bearings support both radial and moderate thrust loads.'), fact('Common applications', 'Motors, wheels, gearboxes, fans'), ], parts: [ part('inner-race', 'Inner race', 'Raceway mounted to the rotating shaft.', 'bearing', vec(-0.25, 0, 0.2)), part('outer-race', 'Outer race', 'Stationary or housing-mounted raceway.', 'bearing', vec(0.25, 0, -0.2)), part('ball-set', 'Ball set', 'Spherical rolling elements carrying load between races.', 'bearing', vec(0, 0.45, 0.25)), part('cage', 'Cage', 'Retainer keeping balls evenly spaced.', 'bearing', vec(0, -0.45, 0.2)), part('shield-seals', 'Shields / seals', 'Protective covers retaining grease and excluding contaminants.', 'housing', vec(0, 0, -0.55)), part('lubricant-film', 'Lubricant film', 'Thin grease or oil film reducing wear and heat.', 'fluid', vec(0.55, 0.25, 0.1)), part('load-vector', 'Load vector', 'Overlay showing applied radial or axial load direction.', 'sensor', vec(0, 0.8, 0)), ], guidedTour: tour([ { id: 'rolling-contact', title: 'Rolling contact', body: 'Balls roll between raceways, replacing sliding friction with rolling friction.', parts: ['inner-race', 'outer-race', 'ball-set'], }, { id: 'cage-speed', title: 'Cage speed', body: 'The cage moves slower than the inner race while maintaining ball spacing.', parts: ['cage', 'ball-set'], }, { id: 'load-zone', title: 'Load distribution', body: 'Only a subset of balls carries most of the load depending on force direction.', parts: ['load-vector', 'ball-set', 'outer-race'], }, ]), related: ['roller-bearing', 'disc-brake-caliper', 'turbocharger'], animation: animation( 'ballBearing', 'rotary', 600, 1, 12000, 4, ['inner-race', 'ball-set', 'cage', 'load-vector'], [ 'Ball orbital speed is derived from pitch diameter and ball diameter.', 'Loaded balls brighten within the current load zone.', ], 1, ), asset: asset('ball-bearing', 2.4), learningObjectives: [ 'Identify inner race, outer race, balls, and cage.', 'Explain rolling friction reduction.', 'Describe basic load distribution.', ], }), defineMachine({ id: 'roller-bearing', title: 'Roller Bearing', subtitle: 'Tapered roller bearing carrying combined radial and axial loads.', category: 'structural', difficulty: 'intermediate', complexity: 5, releaseOrder: 26, createdAt: '2025-01-26', thumbnail: categoryThumbnails.structural, tags: ['bearing', 'roller bearing', 'tapered roller', 'structural'], keywords: ['roller bearing', 'tapered roller', 'preload', 'raceway', 'load path'], description: 'A tapered roller bearing uses conical rollers and raceways whose apexes meet at a common point. This geometry supports high radial loads and axial thrust in one direction, making preload and paired mounting important.', facts: [ fact('Contact type', 'Line contact', 'Rollers spread load over a longer contact line than balls.'), fact('Load capability', 'High radial and axial', 'Tapered geometry reacts thrust loads effectively.'), fact('Adjustment', 'Preload or endplay', 'Bearing life depends on correct mounting clearance.'), fact('Common applications', 'Wheel hubs, gearboxes, differentials, machine spindles'), fact('Design geometry', 'Common apex', 'Roller and race cones meet at a common apex for pure rolling.'), ], parts: [ part('inner-cone', 'Inner cone', 'Inner raceway and flange assembly mounted to the shaft.', 'bearing', vec(-0.25, 0, 0.2)), part('outer-cup', 'Outer cup', 'Outer raceway seated in the housing.', 'bearing', vec(0.25, 0, -0.2)), part('tapered-rollers', 'Tapered rollers', 'Conical rolling elements carrying combined load.', 'bearing', vec(0, 0.45, 0.25)), part('cage', 'Cage', 'Retainer spacing tapered rollers around the bearing.', 'bearing', vec(0, -0.45, 0.2)), part('seal', 'Seal', 'Seal protecting lubricant and excluding debris.', 'housing', vec(0.55, 0, 0)), part('preload-nut', 'Preload nut', 'Adjustment nut setting bearing preload or endplay.', 'fastener', vec(-0.65, 0, 0)), part('load-path', 'Load path overlay', 'Overlay showing combined radial and thrust load path through rollers.', 'sensor', vec(0, 0.85, 0)), ], guidedTour: tour([ { id: 'line-contact', title: 'Line contact', body: 'Rollers spread load along their length, increasing load capacity compared with point-contact balls.', parts: ['tapered-rollers', 'inner-cone', 'outer-cup'], }, { id: 'thrust-load', title: 'Thrust load reaction', body: 'The taper angle allows the bearing to carry axial force as well as radial load.', parts: ['load-path', 'tapered-rollers'], }, { id: 'preload', title: 'Preload adjustment', body: 'The preload nut controls internal clearance, stiffness, and heat generation.', parts: ['preload-nut', 'inner-cone'], }, ]), related: ['ball-bearing', 'bevel-gear-set', 'differential-gear'], animation: animation( 'rollerBearing', 'rotary', 500, 1, 9000, 4, ['inner-cone', 'tapered-rollers', 'cage', 'preload-nut'], [ 'Roller axes are angled to meet the common apex.', 'Preload parameter changes load-zone width and heat indicator.', ], 1, { preload: { label: 'Preload', min: 0, max: 100, step: 5, default: 25, unit: '%', }, }, ), asset: asset('roller-bearing', 2.5), learningObjectives: [ 'Compare point and line contact.', 'Explain why tapered rollers carry thrust load.', 'Identify preload adjustment.', ], }), defineMachine({ id: 'disc-brake-caliper', title: 'Disc Brake Caliper', subtitle: 'Hydraulic brake assembly clamping pads against a rotating rotor.', category: 'structural', difficulty: 'intermediate', complexity: 6, releaseOrder: 27, createdAt: '2025-01-27', thumbnail: categoryThumbnails.structural, tags: ['brake', 'caliper', 'hydraulic', 'friction'], keywords: ['disc brake', 'caliper', 'rotor', 'brake pad', 'piston', 'hydraulic'], description: 'A disc brake caliper converts hydraulic pressure into pad clamping force on a rotor, turning kinetic energy into heat through friction. The model tracks piston actuation, pad movement, rotor speed, and heat buildup.', facts: [ fact('Force source', 'Hydraulic pressure', 'Brake fluid pressure acts on caliper piston area.'), fact('Energy conversion', 'Kinetic to heat', 'Friction between pads and rotor dissipates vehicle energy.'), fact('Friction pair', 'Pad and rotor', 'Material selection balances bite, wear, noise, and heat.'), fact('Common type', 'Floating caliper', 'Slide pins allow one piston to clamp both pads.'), fact('Common applications', 'Cars, motorcycles, bicycles, industrial brakes'), ], parts: [ part('brake-rotor', 'Brake rotor', 'Rotating disc attached to the wheel hub.', 'brake', vec(0, 0, 0.2)), part('caliper-body', 'Caliper body', 'Rigid housing straddling the rotor and supporting pads.', 'housing', vec(0, 0.45, 0)), part('hydraulic-piston', 'Hydraulic piston', 'Piston applying force to the inner brake pad.', 'reciprocating', vec(-0.35, 0.25, 0.25)), part('inner-pad', 'Inner brake pad', 'Friction pad pushed directly by the piston.', 'brake', vec(-0.18, 0, 0.35)), part('outer-pad', 'Outer brake pad', 'Opposing friction pad pulled into contact by caliper reaction.', 'brake', vec(0.18, 0, 0.35)), part('slide-pins', 'Slide pins', 'Guides allowing floating caliper lateral movement.', 'bearing', vec(0.55, 0.45, 0)), part('hydraulic-port', 'Hydraulic port', 'Brake fluid inlet from the master cylinder.', 'fluid', vec(-0.65, 0.65, 0)), part('bleed-screw', 'Bleed screw', 'Service screw used to remove air from the brake hydraulic circuit.', 'fastener', vec(0.65, 0.7, 0)), part('heat-indicator', 'Heat indicator', 'Overlay displaying rotor temperature rise during braking.', 'sensor', vec(0, -0.75, 0)), ], guidedTour: tour([ { id: 'hydraulic-force', title: 'Hydraulic force', body: 'Brake pressure pushes the piston, which drives the inner pad toward the rotor.', parts: ['hydraulic-port', 'hydraulic-piston', 'inner-pad'], }, { id: 'clamping', title: 'Clamping the rotor', body: 'Reaction through the caliper body brings the outer pad into contact so both sides clamp the rotor.', parts: ['caliper-body', 'outer-pad', 'brake-rotor', 'slide-pins'], }, { id: 'heat', title: 'Energy becomes heat', body: 'Friction slows the rotor and raises pad and rotor temperature.', parts: ['brake-rotor', 'inner-pad', 'outer-pad', 'heat-indicator'], }, ]), related: ['hydraulic-cylinder', 'ball-bearing', 'v8-engine'], animation: animation( 'discBrakeCaliper', 'hybrid', 600, 0, 2000, 5, ['brake-rotor', 'hydraulic-piston', 'inner-pad', 'outer-pad', 'heat-indicator'], [ 'Pad displacement responds to brake pressure and closes the running clearance.', 'Rotor speed decays under friction torque and heat indicator integrates dissipated energy.', ], 1, { brakePressure: { label: 'Brake pressure', min: 0, max: 120, step: 2, default: 20, unit: 'bar', }, }, ), asset: asset('disc-brake-caliper', 3), learningObjectives: [ 'Trace hydraulic pressure to pad clamp force.', 'Explain friction energy conversion into heat.', 'Identify floating caliper slide pins.', ], }), defineMachine({ id: 'turbocharger', title: 'Turbocharger', subtitle: 'Exhaust-driven compressor using turbine energy to boost intake pressure.', category: 'structural', difficulty: 'advanced', complexity: 8, releaseOrder: 28, createdAt: '2025-01-28', thumbnail: categoryThumbnails.structural, tags: ['turbocharger', 'compressor', 'turbine', 'forced induction'], keywords: ['turbocharger', 'compressor wheel', 'turbine wheel', 'wastegate', 'boost'], description: 'A turbocharger couples an exhaust turbine to an intake compressor on a shared high-speed shaft. The model separates hot and cold housings, bearing cartridge, wastegate, and oil/coolant services for clear guided learning.', facts: [ fact('Energy source', 'Exhaust enthalpy', 'The turbine recovers energy from hot exhaust gas.'), fact('Purpose', 'Boost pressure', 'The compressor raises intake air density for more engine power.'), fact('Shaft speed', '80,000-250,000 rpm', 'Small turbochargers can spin extremely fast.'), fact('Control', 'Wastegate or variable geometry', 'Bypass control limits boost and turbine speed.'), fact('Common applications', 'Diesel engines, petrol engines, aircraft auxiliaries'), ], parts: [ part('turbine-wheel', 'Turbine wheel', 'Hot-side wheel driven by exhaust gas.', 'rotating', vec(0.65, 0, 0.2)), part('compressor-wheel', 'Compressor wheel', 'Cold-side wheel compressing intake air.', 'rotating', vec(-0.65, 0, 0.2)), part('shaft', 'Shared shaft', 'High-speed shaft coupling turbine and compressor wheels.', 'rotating', vec(0, 0, 0)), part('bearing-housing', 'Bearing housing', 'Center cartridge supporting the shaft and routing oil.', 'bearing', vec(0, -0.45, 0)), part('wastegate', 'Wastegate', 'Bypass valve controlling exhaust flow around the turbine.', 'valve', vec(0.95, 0.45, 0)), part('turbine-housing', 'Turbine housing', 'Hot volute directing exhaust gas onto the turbine wheel.', 'housing', vec(0.85, 0, -0.35)), part('compressor-housing', 'Compressor housing', 'Cold volute collecting compressed intake air.', 'housing', vec(-0.85, 0, -0.35)), part('oil-coolant-ports', 'Oil and coolant ports', 'Service ports lubricating and cooling the bearing cartridge.', 'fluid', vec(0, -0.85, 0)), ], guidedTour: tour([ { id: 'energy-recovery', title: 'Exhaust energy recovery', body: 'Hot exhaust expands through the turbine housing and spins the turbine wheel.', parts: ['turbine-housing', 'turbine-wheel'], }, { id: 'shared-shaft', title: 'Shared high-speed shaft', body: 'The turbine wheel drives the compressor wheel through a compact high-speed shaft and bearings.', parts: ['turbine-wheel', 'shaft', 'compressor-wheel', 'bearing-housing'], }, { id: 'boost-control', title: 'Boost control', body: 'The wastegate bypasses exhaust around the turbine to control shaft speed and intake boost.', parts: ['wastegate', 'compressor-housing', 'oil-coolant-ports'], }, ]), related: ['diesel-engine', 'jet-engine-turbojet', 'turbofan-engine', 'ball-bearing'], animation: animation( 'turbocharger', 'thermal', 90000, 5000, 250000, 5, ['turbine-wheel', 'compressor-wheel', 'shaft', 'wastegate'], [ 'Compressor and turbine wheels share identical shaft speed but different flow coloration.', 'Wastegate opening reduces turbine torque and boost pressure readout.', ], 1, { wastegateOpening: { label: 'Wastegate opening', min: 0, max: 100, step: 1, default: 15, unit: '%', }, }, ), asset: asset('turbocharger', 3.2), learningObjectives: [ 'Explain how exhaust energy drives intake compression.', 'Identify hot side, cold side, and bearing cartridge.', 'Describe wastegate boost control.', ], }), ] as const satisfies readonly MachineDefinition[]; export type CoreMachineDefinition = (typeof coreMachineDefinitions)[number];