HOPLITE
037
Before a factory buys a robot cell, it needs to know whether the robot can actually pick the part out of the bin. Hoplite 037 answers that question in the browser.
You upload a 3D model of the part, describe the bin, the gripper and the robot, and the app drops virtual parts into the bin. Each one ends up in a bucket: Pickable, Occluded, Grasp Collision, World Collision, Rejected Orientation or Unreachable.
Everything runs client-side. The CAD file never leaves the browser, and there is no backend to set up.
One question
per screen.
The app is a seven-step wizard: Target, Bin, Gripper, Robot, Pick Point, Layout, Results. Each screen asks one thing, and every answer is kept in a single shared store.
The steps only write to the store. The Results step reads it and runs the test, so there is one place where every input lives.
Seven questions,
one answer.
Cheap to ask,
expensive to find out.
A bin-picking cell is a large purchase, and the first real trial usually happens after it is bought. Hoplite 037 moves that first estimate earlier, to the engineer's laptop.
Each virtual part runs through checks in a fixed order: tilt, gripper fit, collisions, hidden-ness, then reach. The first check a part fails decides its bucket. The slowest check, reach, goes last so it only runs for parts that passed everything else.

A physics engine,
used as a ruler.
Rapier runs in the browser as WebAssembly, but the world is never stepped. There is no settling and no falling — only one-shot geometric questions asked of static shapes: does this box overlap that one, and what does a ray hit?
Reachability uses a hand-written inverse-kinematics solver. It nudges the robot's joints up to 100 times, respecting each joint's limits, and tries four starting poses before it gives up and calls a part Unreachable.


A tool for early
decisions should say
how early it is.
The estimate is
only as honest
as its limits.
const deviation = maxAxisDeviationDeg(pose.rotation, pickPointRotation);
if (deviation > symmetryToleranceDeg) {
bucket = 'rejectedOrientation';
}
if (!bucket) {
const fitsX = gripper.footprint[0] <= partDimensions[0] * 1.2;
const fitsZ = gripper.footprint[2] <= partDimensions[2] * 1.2;
if (!fitsX || !fitsZ) bucket = 'graspCollision';
}Parts and grippers are boxes, grasp checks are rules of thumb, and the robot preset is marked unverified. Keeping those limits on screen is part of the product: every result is an early estimate, to be confirmed with a real trial.