Prevent AI positioning elements at 0,0 when brush: none provided (#8768)

This commit is contained in:
Clément Pasteau
2026-06-25 16:35:14 +02:00
committed by GitHub
parent b2222005d9
commit be139cee76
2 changed files with 76 additions and 2 deletions
@@ -1892,6 +1892,59 @@ describe('editorFunctions', () => {
});
});
// Regression test: creating instances with the "none" brush used to leave
// every new instance at the origin (0,0) instead of at brush_position.
it('creates new instances at brush_position with the none brush', async () => {
await putInstances({
brush_kind: 'none',
brush_position: '200,300',
new_instances_count: 2,
});
expect(getInstancePositions(testScene)).toEqual([
{ x: 200, y: 300 },
{ x: 200, y: 300 },
]);
});
// The none brush must still leave existing instances where they are.
it('does not move an existing instance edited with the none brush', async () => {
await putInstances({
brush_kind: 'point',
brush_position: '100,200',
new_instances_count: 1,
});
const [created] = getInstances(testScene);
await putInstances({
brush_kind: 'none',
brush_position: '640,360',
existing_instance_ids: created.uuid,
instances_size: '48,48',
});
expect(getInstancePositions(testScene)).toEqual([{ x: 100, y: 200 }]);
});
// Editing an existing instance with the none brush and no brush_position
// must not snap it to the scene-center fallback.
it('does not move an existing instance edited with the none brush and no brush_position', async () => {
await putInstances({
brush_kind: 'point',
brush_position: '100,200',
new_instances_count: 1,
});
const [created] = getInstances(testScene);
await putInstances({
brush_kind: 'none',
existing_instance_ids: created.uuid,
instances_opacity: 128,
});
expect(getInstancePositions(testScene)).toEqual([{ x: 100, y: 200 }]);
});
// line/grid need an end position to spread instances. Omitting it must fail
// up front (and create nothing) rather than silently dropping every
// instance at the default origin.
+23 -2
View File
@@ -3128,6 +3128,13 @@ const put2dInstances: EditorFunction = {
'The brush kind is unknown and was considered to be "none" instead.'
);
}
// "none" keeps existing instances in place; new ones still need a position.
modifiedAndCreatedInstances.forEach(instance => {
if (!existingInstanceStates.has(instance)) {
instance.setX(brushPosition[0]);
instance.setY(brushPosition[1]);
}
});
}
const instancesSize = SafeExtractor.parseCommaSeparatedTwoFiniteNumbers(
@@ -3177,7 +3184,10 @@ const put2dInstances: EditorFunction = {
objectSizeInfo.height !== null
? [objectSizeInfo.width, objectSizeInfo.height]
: null;
if (brush_kind === 'point' && effectiveSize) {
if (
(brush_kind === 'point' || brush_kind === 'none') &&
effectiveSize
) {
attrs.push(
`origin at this position, each occupies ${getOccupiedSpaceDescription(
brushPosition,
@@ -3773,6 +3783,14 @@ const put3dInstances: EditorFunction = {
'The brush kind is unknown and was considered to be "none" instead.'
);
}
// "none" keeps existing instances in place; new ones still need a position.
modifiedAndCreatedInstances.forEach(instance => {
if (!existingInstanceStates.has(instance)) {
instance.setX(brushPosition[0]);
instance.setY(brushPosition[1]);
instance.setZ(brushPosition[2]);
}
});
}
const instancesSizeArray = SafeExtractor.parseCommaSeparatedThreeFiniteNumbers(
@@ -3820,7 +3838,10 @@ const put3dInstances: EditorFunction = {
objectSizeInfo.depth !== null
? [objectSizeInfo.width, objectSizeInfo.height, objectSizeInfo.depth]
: null;
if (brush_kind === 'point' && effectiveSize) {
if (
(brush_kind === 'point' || brush_kind === 'none') &&
effectiveSize
) {
attrs.push(
`origin at this position, each occupies ${getOccupiedSpaceDescription(
brushPosition,