Probably like all devs I'm wondering what my future holds now that AI is meant to be able to code like a dev guru mainlining sugary beverages. I'm dipping my toe in with Windsurf and Cascade. Should I be thinking about a new career? Here's my experience so far.
But I wouldn't fly on a passenger jet with a fly-by-wire system written by AI just yet.
Introducing Windsurf & Cascade AI
Windsurf (formerly Codeium) is a software company that started working on an AI coding assistant add-on for the myriad of code editing products like VSCode, JetBrains, etc. They then pivoted into providing their own VSCode-based browser named 'windsurf' and have now rebranded to use that name for the company. They still provide AI coding assistants for other browsers and continue to expand that coverage.
Their AI assistant, Cascade, can be set to use various of the worlds AI's - when I carried out this work I used Claude 3.5 Sonnet.
I use a paid plan and I code in TypeScript.
I've been experimenting with Windsurf for a couple of weeks.
LLM constraints for Konva?
I should point out that my interest is Konva and as far as LLM's are concerned subject matter for Konva may be of quite low volume. So some of what I am about to report should be considered with that in mind.
The Case: Subtracting matrices.
Konva is a JavaScript 2D graphics library for the HTML5 canvas. It uses vector math to control position and other attributes of the shapes that it displays. Vector math means affine transformations, or in Konva terms, transformation matrices.
Transformations make my head hurt. So I was hoping for some useful input from the AI.
Setting the scene
In Konva we can nest containers. So we can have a stage container, then a layer container, then a group container and finally a shape within that group. Here's a diagram to help explain.
Stage
└─ Layer
└─ Group
└─ ShapeEach of those containers has its own co-ordinate system. And all of the named things - call them nodes - have their own transformation matrix. Taking position as an example, this allows the Shape to only be concerned about its position in the Group that contains it. And Group's position is set relative to Layer, and Layer to Stage. Which is a great benefit when working with the HTML5 canvas which has no such built-in object model.
Now - I have a particular challenge to do something new that I have not done before. I know the territory, but not the detail.
The task is to achieve the structure below, where new shape B is on the same layer as Shape A, and is positioned precisely on top of existing shape A.
Stage
└─ Layer
└─ Group
└─ Shape A
└─ Shape B
If you are new to the subject, or prefer to try to avoid the detail like me, you might intuit that the answer is something close to
Actually, this gets slightly more complex in Konva as there are two transform-giving methods
// get the total transform inc all ancestor containers
node.getAbsoluteTransform()
// get only the transform relative to immediate parent container
node.getTransform()
The difference is important in the conversation with the AI, as you'll see.
I went ahead and coded up a simple solution
// Get total transform matrix of shape A
Const shapeA_absTransform = shapeA.getAbsoluteTransform()
// Apply to shape B
shapeB.setAttrs(shapeA_absTransform.decompose())
// works because decompose converts the matrix to a plain JS object
// with the usual Konva attributes for x, y, scaleX, scleY, etc,
// so we can apply it easily via setAttrs().But that fails. As you can see, the blue rect is not precisely positioned over the red.

So I asked the AI
[AI response starts]
Great question! Even on the same layer, using absolute transform directly won't work because of "double transformation". Here's why:
Stage
└─ Layer (has transform)
└─ Shape A (position = absolute transform includes Stage + Layer + Shape transforms)
└─ Shape B
If you do:
shapeB.setAttrs(shapeA.getAbsoluteTransform().decompose())What happens is:
- You get Shape A's absolute transform which includes: Layer + Shape A transforms
- You apply this to Shape B
- But Shape B is already on the layer, so it automatically gets transformed by: the Layer's transform
- Result: Shape B gets transformed by: (Layer + Shape A) + Layer
- The Layer transform is applied TWICE!
This is why to position Shape B correctly, you need to remove the layer transform first:
const layerTransform = shapeA.getLayer().getTransform();
const shapeAbsTransform = shapeA.getAbsoluteTransform(); // Layer + Shape
const layerInverse = layerTransform.copy().invert();
const relativeTransform = layerInverse.multiply(shapeAbsTransform); // Just Shape A's transform
shapeB.setAttrs(relativeTransform.decompose()); // B positioned correctly
Or more simply, if Shape A isn't in any groups, just use its own transform:
shapeB.setAttrs(shapeA.getTransform().decompose())[AI response ends]
Firstly, I liked the tone and clarity of the response. And the double-transformation the AI mentioned seemed to explain what I was seeing - the blue rect has slightly greater x & y than the original red. Looks credible.
So I coded up the first solution it suggested. This gets the layer transform, inverts it and multiplies it against the original shape's absolute transform to get the transform from the layer up, then applies the result to the second shape.
Did it work? No.
The additional x & y of the blue rect are less, but the shapes are not precisely positioned. What could be wrong.
I went through my code. I noticed that the stage had its own transformation in the form of an x & y value being applied. I commonly change the x & y and scale values of the stage and layer to ensure I don't overlook any ill affects this could have on my work.
And the AI had not considered this stage transformation matrix.
So I asked it a clarifying question.
[AI response starts]
Ah, you're absolutely right! I apologize for my previous explanation. Let me correct this.
If the stage is moved from (0,0), then using getTransform() on the layer would miss the stage's contribution to the layer's position. You are correct that we should use getAbsoluteTransform() for the layer.
Here's the corrected version:
// Get Shape A's complete position including all transforms
const shapeAbsTransform = shapeA.getAbsoluteTransform();
// Get layer's complete position including stage transform
const layerAbsTransform = shapeA.getLayer().getAbsoluteTransform();
// Remove layer+stage transforms to get position relative to stage
const layerInverse = layerAbsTransform.copy().invert();
const relativeTransform = layerInverse.multiply(shapeAbsTransform);
// Apply to Shape B
shapeB.setAttrs(relativeTransform.decompose());This is more correct because:
shapeAbsTransformincludes: shape + group + layer + stage transformslayerAbsTransformincludes: layer + stage transforms- When we invert and multiply, we properly remove both layer and stage transforms
- The resulting
relativeTransformwill be correct regardless of where the stage is positioned
Thank you for catching this! This is a subtle but important distinction when dealing with transformed stages.
[AI response ends]
So the bug was the use of layer.getTransform() instead of what it should have been, layer.getAbsoluteTransform().
I modified the code as the Ai suggested, and now it works. Its not much to look at but note there is no red rect visible - this is because the process placed the blue rect precisely over the red. That was the mission = mission success!

Since I was on a real-world task I went on to experiment and tried to make a bullet-proof function to position one shape over another. In case you're interested in the mission as well as the AI info, my findings were:
- The layers must have the same transformations.
- The approach works when the layers are scaled
- It works regardless of the group ancestors of the two shapes being different, for example shape A in a group and shape B not.
- It also works when the shapes are on different layers so long as the layers have their transformations equalised.
Conclusion
The AI gave me a partial answer but it didn't cover all the possibilities. Specifically the fact that there was a stage transformation, which is common if your app uses zoom-at-a-point or allows the user to scroll / pan the stage. So it should be a consideration for the AI to understand.
The AI did realise its mistake and gave me the corrected solution, though by that time I had worked it out myself.
My thoughts are that I need to be careful when relying on code that the AI suggests. I need to consider the prompt I give it and ensure I give an accurate context. Though it would have been nice to have been asked about stage transformations in the scenario above. It feels like that would be a gotcha that an expert would have experienced and be ready to raise with an apprentice, like me.
On the plus side, the Windsurf editor is just as good as VSCode for actual manual editing. The code suggestions and code completion that Cascade (the Windsurf AI coding companion) suggests are ok around 50% of the time and get better the longer you code and the more code you have in the project.
Sometimes it knows exactly what I'm going to write next and this is where the productivity gain comes - I press tab to accept its suggestions and job done! Its great when changing variable names in multiple places when you typed the wrong one by mistake, for example.
Sometimes the code it suggests is definitively not relevant, which is where the next word probability approach of the current crop of 'AI' tools use can fall down.
Having it watch for typos in my comments is great, And having it suggest comments is useful but often it copies most of an earlier comment when the context should be different.
I've let it explain some of my TypeScript linting blunders so its helped me avoid the overuse of any that would otherwise have happened (TS coders will know what I mean).
Reflecting on these results, I'm reminded of that point I made early on about Konva being a small volume topic as far as LLM learning is concerned and that LLM's return higher quality results when they have more material to learn from. This point would likely carry over to a lot of JavaScript libraries which aren't mass-market adopted. Same for any non-coding subject where learning material is scarce.
Will I carry on with Windsurf? Yes. It is good and usable already and I'm hoping it will learn more about my approach and style, and I'll learn about how to write better prompts.
Thanks for reading.
VW. April 2025