Skip to content

p5.Matrix made public #7754

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
2 of 17 tasks
ksen0 opened this issue Apr 18, 2025 · 10 comments
Open
2 of 17 tasks

p5.Matrix made public #7754

ksen0 opened this issue Apr 18, 2025 · 10 comments

Comments

@ksen0
Copy link
Member

ksen0 commented Apr 18, 2025

Increasing access

The access statement covers technical maintenance and improvements in the following way:

We believe consistency of the tool makes it more accessible for beginners. Examples of feature requests that improve accessibility include: Performance increases for people using less powerful hardware; Consistency in the API

Making p5.Matrix available for both general and WEBGL use can support beginners who are using p5.js to encounter and learn mathematical concepts, which are important to many creative coding practices.

Most appropriate sub-area of p5.js?

  • Accessibility
  • Color
  • Core/Environment/Rendering
  • Data
  • DOM
  • Events
  • Image
  • IO
  • Math
  • Typography
  • Utilities
  • WebGL
  • Build process
  • Unit testing
  • Internationalization
  • Friendly errors
  • Other (specify if possible)

Feature enhancement details

p5.Matrix is currently a private class that is used extensively for WEBGL and provides some general-purpose math functions. The goal is to make it public in a way that supports beginners to both graphics usage and mathematics more generally.

@ksen0 ksen0 moved this to In Progress in p5.js 2.x 🌱🌳 Apr 18, 2025
@ksen0 ksen0 moved this from In Progress to Open for Discussion in p5.js 2.x 🌱🌳 Apr 18, 2025
@ksen0
Copy link
Member Author

ksen0 commented Apr 18, 2025

Input is welcome on criteria to make p5.Matrix more supportive of beginners. You can find the current implementation in the dev-2.0 branch.

@ksen0 ksen0 added this to the 2.1 milestone Apr 18, 2025
@Mamatha1718
Copy link

Hi @ksen0 👋,

I would like to tackle this issue, From what I understand, the main goal is to make p5.Matrix publicly available and beginner-friendly — both for general use and WebGL — so that it helps folks learn matrix math more easily through p5.js.

I’m thinking of working on refactoring it to a more general location (like src/math/), making the API simpler and consistent, and then adding beginner-focused documentation and examples. Before diving in, I wanted to check with you:

=> Which files should I focus on for making the Matrix class public and usable?
=> Where should I update/add documentation and examples?
=> Is there anything specific you’d like to see in terms of the beginner experience?

Thanks in Advance 😊

@GregStanton
Copy link
Collaborator

GregStanton commented Apr 21, 2025

Hi all!

I think it might help for us to start with a bit of context on what's been done, as well as a list of next steps. As I'll explain below, I think the top priority is to get a better idea of the feature set, and then to work on the API. Sorry this post is so long. I have a lot to say, apparently 😅 But I do hope that this post will be helpful!

@Mamatha1718 Hello! 👋 You can take a look at the current code that @ksen0 shared, if you'd like. (These features are in src/math, but only in the dev-2.0 branch.) Your feedback is very welcome!

Note: I've been involved in the discussions but haven't worked on this part of the code myself, so I'll ping some of the other contributors in case I'm missing anything important.

Current state of p5.Matrix

I just reviewed some previous discussions related to matrix features and extensions of p5's math features generally, going back to 2021: #5210, #6527, and #6765. My sense is that there was rough consensus of support for a few things:

  • Adding a public matrix class (as a start, before considering any other major additions to the math functionality)
  • Improving performance, code organization, and interoperability with other libraries
  • Deciding on features, then API, then implementation

I think @limzykenneth may be able to confirm or correct me on that summary of past discussions. Since then, my understanding is that @holomorfo has done the following:

  • implemented approaches from numJS (in MatrixNumjs.js) and glMatrix, for performance comparisons (are we keeping both?)
  • improved code organization
  • generalized some vector and matrix features e.g. ($n$-dimensional vectors are now mostly supported by p5.Vector)
  • added documentation (the $n$-dimensional functionality doesn't seem to be fully reflected in the docs yet, but I think the existing matrix features all have some documentation)

Taking a step back, the recent proposals for the math features in 2.0 were much broader, so a lot of the discussion wasn't directly related to matrices. In particular, I don't think there was a ton of discussion on the problems solved by exposing matrices, the desired feature set, or the API. I think those discussions are still needed (mainly around the features and API).

Motivation: What problems does p5.Matrix solve for users?

I think there was consensus for exposing p5.Matrix, mainly because p5 already uses this functionality internally, so exposing it is a minimal way to try expanding p5's math functionality. I'll list some overall problems that would be solved by exposing this functionality, to help with selecting and designing features. Please let me know if I missed anything :)

  1. Accessibility for contributors At the top, @ksen0 quoted the access statement, which says that consistency improves accessibility for beginners. I think this extends into the codebase itself, which has its own internal APIs and documentation (or a lack thereof). In particular, matrices are applied a bunch internally, and I expect new applications in the future. Organizing the features for general reuse, vetting the API for public use, and providing reference documentation can only improve the quality of the codebase itself. And publicly teaching these features to users makes the onramp for contributing to matrix-heavy parts of p5 that much smoother.

  2. Accessibility for users
    a. Consistency and predictability The p5 library already has p5.Vector and some matrix features, such as applyMatrix() and resetMatrix(). Users would naturally expect p5 to have a p5.Matrix class, especially since three.js has matrices, babylon.js has matrices, two.js has matrices, etc.
    b. Reusuable foundation for data work Working with data is one of the original inspirations for Processing, and it's a theme in this year's Processing Foundation fellowships. Linear algebra is fundamental for this. Want to fit a curve to data? Linear algebra. Want to get a feel for what your high-dimensional data looks like? Linear algebra. Want to do any of this with p5? You're currently out of luck. Although it may not make sense for p5 to have more specialized matrix algorithms, it may still be useful for it to provide a foundation for add-on libraries that want to go a step further. For example, a library like Mathemagical.js (a p5 library I started), might benefit from more specialization. But making a well-designed matrix class that works seamlessly with p5? That's not so easy. It's much easier if the p5 community can work together to provide a foundation for data or math intensive add-on libraries.
    c. Gentler learning curve for graphics Currently, p5 introduces matrices to users via applyMatrix(). In short order, the reference page goes from explaining that a matrix is a table of numbers, to explaining that those numbers are used to multiply points, to the examples shown below (these are the very simplest examples that are provided). As a math educator, it's clear to me that the learning curve here is far too steep. This isn't an issue with the documentation. The problem is that no scaffolding is provided in the form of simpler features, to help users climb up. Even for students who know some linear algebra, this will be confusing. For something as fundamental as matrices, more feature scaffolding may be pretty valuable (especially alongside some tutorials).

3x3 4x4
Image Image

Proposed next step: Refine the feature set

Internally, p5's matrix features were designed for very specific purposes in computer graphics. But, as discussed above, the overall context of p5 may call for a more general feature set.

The main data structure (or data structures)

I think there are some design constraints that I'm not totally aware of; @davepagurek may have a better idea. But, my own current feeling is that the data structure that makes the most sense for p5 is a general $m \times n$ (rectangular) matrix, where $m$ and $n$ may or may not be equal.

Some reasons:

  • Reusability There are plenty of instances when working with data and visualizing it calls for rectangular matrices. Want to visualize two planes in three dimensions? No problem. Want to visualize the intersection of those planes? A user might try using a rectangular matrix for that.
  • Consistency Students who study matrices in math classes won't generally assume matrices are square. Also if we put p5.Matrix in the math module alongside the now n-dimensional p5.Vector objects in 2.0, as I think we should, users will won't expect the possible dimensions to be bounded to 2, 3, or 4. If we put these two expectations together, we get rectangular matrices. All this makes it easier for users to work with high-dimensional data.
  • Not too special, not too general For the core of p5, I'm guessing that a more general data structure, like the tensors @nickmcintyre developed for número, might be a bit overwhelming for a lot of users (I'm not sure, though). In any case, I'd hope we could design a general matrix class so that it could be easily extended to a tensor class, or at least so that its API could be extended seamlessly? If we can successfully design p5.Matrix so that it effectively works as an extension of p5.Vector, then maybe a tensor class could extend p5.Matrix in the same way? I haven't thought about the details here. As an example, we might treat matrix-vector multiplication the same way whether a vector is represented as an $n \times 1$ matrix or an $n$-dimensional p5.Vector instance.

The main operations

I wonder if it might be beneficial to have some kind of separation between general math features and specialized features for graphics? Maybe not. But if so, how? It's all fundamentally math, but there seems to be a fairly natural separation. (The feature list below is rough, but I think it gets the general idea across.)

Math

  • Reading and writing
    • convert matrix to nested array
    • convert nested array to matrix
    • set a new matrix using an old matrix
    • get, set general submatrices (possibly w/ convenience functions for rows, cols, $1 \times 1$ submatrices)1
    • get, set diagonal elements if that's helpful
    • set/reset to identity matrix, maybe zero matrix
  • Arithmetic
    • add ($m \times n$ + $m \times n$)
    • multiply (possibly with overloads as in two.js)
    • determinant ($n \times n$)
    • trace ($n \times n$) (could maybe omit, but may be expected if determinant is supported)
    • transpose ($m \times n$)
    • inverse ($n \times n$ invertible matrices)
  • Algebra
    • linear-system solving, with least-squares solution when appropriate (requires discussion)2

Graphics

  • normal matrix (convenience feature based on submatrix, transpose, inverse features?)
  • setters (convenience features based on general setter feature)
    • set rotation matrix 3
      • Input: angle, and optionally, an axis when applicable
      • Option or mode for number of spatial dimensions, and for linear or affine?
      • Could consider further convenience functions for specifically rotating about coordinate axes
    • set scaling matrix (uniform or non-uniform, i.e. each coordinate axis gets its own scale factor)
    • set translation
    • set perspective matrix
    • set orthographic projection matrix

Separation strategy: If it makes sense to separate these types of features (I'm not sure yet if it does), we might consider naming conventions, or simply different submodule names for a logical separation in the reference, or... probably not different classes I guess, right?

Phase strategy: Alternatively, we might only expose general math features to start, since those would be more reusable (in particular, they'd be sufficient for recreating all the graphics functions), since they're arguably necessary for consistency with $n$-dimensional vectors, and since they provide simpler scaffolding to more advanced concepts like affine and projective transformations? Regardless, we'd ideally have a plan in mind about how the general math and specialized graphics features would coexist before exposing either.

API

I have a list of questions/ideas about the current p5.Matrix API, but I think it may be good if we can get a better sense of the feature set first. For now, some general questions and design considerations:

  1. Mutate or return new objects? Or both, but distinguished with a naming convention? Where did we come down on this?
  2. Want interoperability with other libraries if possible.
  3. To what extent might we be bound by a need to be consistent with applyMatrix()? If we want more flexibility, what workarounds might there be? (For example, specifying matrices with flat arrays may not be the most intuitive for general math usage.)

Inspiration

For now, I'm just parking this fairly random and not-meant-to-be-exhaustive-or-representative list of existing libraries here. I figure we might take design inspiration from it. I may come back and add more or annotate it more, if it looks like it might be helpful. I collected some of these from the old discussions, but I didn't try to list everything. If anyone wants me to add anything, just let me know.

Updates:

  1. Added trace to the proposed feature set, for consideration.
  2. Added linear-system solving (with least squares when appropriate), for consideration, per suggestion from @davepagurek.
  3. Added to list of sources for inspiration.

Footnotes

  1. Subsets of matrix elements (rather than submatrices) might be useful for some purposes, but I'm guessing that might be too much for the core of p5.

  2. It'd probably make sense to only include a version of MATLAB's A \ B, not A / B. The latter is used infrequently and could be obtained by combining A \ B and A', where the latter denotes the transpose operation, via B/A = (A'\B')'. See MATLAB's documentation of linear-system solving, and their documentation for A \ B for inspiration.

  3. For anyone who's curious and knows some math but not much graphics, or vice versa, you might find these Wikipedia explanations helpful: the article on rotation matrices, a coordinate-wise explanation of affine transformations and projective transformations, and a a block-matrix explanation of affine transformations

@davepagurek
Copy link
Contributor

Just a little extra info to frame the discussion: although WebGL is primarily the current user of p5.Matrix (2D mode uses the built-in js canvas which handles its own matrices using the DOMMatrix API), we would be expecting both WebGL and 2D mode users to make use of it as a way to represent the transformations done in p5 as an object. 2D transformations are probably the easiest way to introduce the concept of a matrix, and the graphics concepts apply there too.

For separating general math/graphics applications: in broader math, matrices are a very general tool, while in graphics there is a specific way of interpreting the data that may not apply in the general case. Some examples:

  • rotation/translation/scale methods, as Greg mentioned (these are only well defined on specific sizes of matrices, and have specific interpretations of the outermost row/column)
  • methods for perspective projection, ortho, frustum, etc (these imply a specific use of the matrix)
  • multiplyPoint and multiplyDirection (both are variants of multiplying an size-n+1 square matrix by a size-n vector: points add a 1 as an additional row, directions add a 0. this is a very specific interpretation of matrices as affine and representing specific concepts.)

My 2 cents is that it's not worth trying to generalize those methods to work across the board. I think the use case is less clear as you generalize those (even though it's still valid), and it's more easily explained when we can have the specific graphics use case built-in. Additionally, we may need a different implementation for the graphics ones to keep them fast. So a possible way forward could be:

  • Have a general n-by-m matrix class that you can do just general matrix operations on
    • This could be based on the numjs implementation, but with the graphics-specific APIs removed
    • In addition to Greg's list, maybe it's also worth implementing something like Matlab/Julia A \ B which solves Ax=B for x using least squares for rectangular matrices, as that's a very common tool to reach for in data analysis settings?
  • Have a graphics-specific implementation of a common interface that adds graphics-specific methods and restricts matrix sizes
    • For this we want to be able to assume 3x3 and 4x4 affine matrices only
    • This should likely continue to be based off of glMatrix. We can keep our custom version of that code, or slowly shift to using glMatrix as a dependency (p5.Matrix mostly acting as an interface adapter) to clean up the codebase
    • On top of this, there are some graphics-specific things that should probably just be internal and not public-facing, e.g. the .mat4 property, which has a specific interface needed for WebGL

@davepagurek
Copy link
Contributor

For naming, I'm currently thinking the graphics-specific one could be called something like TransformationMatrix? I'd like to avoid GL in the name because it's useful for graphics in general, not just WebGL, as a way to represent spatial transformations. I'm also thinking that Affine could be left out of the title because it's fairly technical (a user could interface with the objects without having to think about its underlying representation being affine), and also potentially too general (you could have higher dimensional affine spaces too, but I don't think that needs to be within scope.) TransformationMatrix isn't perfect, as Transformation is pretty general-sounding too, but it at least shares language with our existing docs on coordinates. I'm open to more suggestions though!

@holomorfo
Copy link

Hi team, I also want to add my two cents since I've been working on the Matrix revamp since last year. I feel that there are two main directions here:

  • Originally the Matrix class was mainly for internal rendering, this approach followed the gl-matrix implementation in detail, and this is where many of the hardcoded and fixed dimentional (3x3 and 4x4) version of the methods come from. This was done for performance reasons, you can compare the methods from this library to see that the implementation was made in a very similar manner glmatrix, mult
  • Now we want to have a generic Matrix implementation for didactic and exploration (non-render) purposes

These two are not necessarily compatible, since having (nxm)-dimentional operations in a performant way is a challenging issue. In this direction, the request was to explore if we could implement other Matrix impelmentations that would help us. I created an initial MatrixInterface which would allow us to plug and play with other libraries, initially I created the numjs implementation and it worked correctly for n-squared matrices.

As a next step we should have a generic implementation of nxm matrices, however the challenge is to still be compatible with the existing render API. So the greatest challenge is to make this render performant AND flexible and compatible.

I agree with Dave that we might need to have an internal optimized Matrix class with the gl implementation only for render, and have a secondary Matrix didactic version. that we can export to the user, completely decoupled with the render process.

In this new didactic Matrix class we can establish new guidelines like modification in place or copy a new object, etc.

I would like to continue this effort or collaborate with whoever might be working on it since its really tricky to do the modifications while not breaking existing functionality and maybe I can provide some insight.

Thanks

@Mamatha1718
Copy link

@davepagurek , @holomorfo , @GregStanton Thanks for the clarification!

I checked matrix.js and matrixNumjs.js — looks like m×n matrices are technically supported via NumJS, but it’s still unclear if general matrices will be part of the public p5.Matrix API.

Also, I noticed most methods like add() return new matrices instead of mutating them, so I get that the design is still being worked out.
Thanks in Advance!

@GregStanton
Copy link
Collaborator

GregStanton commented Apr 22, 2025

Hi all! There's a lot to chew on here. I'll share some thoughts about what's been discussed so far. I'm trying out collapsed-section formatting instead of headings so that the details don't clog up our discussion. Also, I've edited this comment a fair amount since publishing it, just FYI; I didn't make a log of my edits since it doesn't look like anyone has read it yet.

Generality @davepagurek Thanks for all your great ideas! I agree that we don't need to generalize the graphics-specific features to higher dimensions. Also, to summarize the conversation so far, it looks like there's an initial consensus around supporting rectangular matrices (at least among the participants so far).
Linear-system solving (and trace) I added linear-system solving to the potential-feature list in my previous comment, as well as trace (I omitted a trace feature originally since we could maybe get by without it, but I think it's natural to predict that trace would be supported if determinant is, so I added it for consideration).

I think linear-system solving could make a lot of sense for the core of p5:

  • [utility] I was going to have to develop or borrow a linear-system solver to implement arcVertex() anyway, so we already have one internal use case for the feature (in that case, we’d want an exact solution to a rectangular system with five equations and six unknowns). It might open up the possibility of other core features (like fitting curves to vertices), and users would probably find many use cases (in fact, the example I already gave of visualizing the intersection of two planes would be covered). In general, solving a system of linear equations is one of the most fundamental problems in technical computing, and the most fundamental problem in linear algebra.
  • [cohesion] We probably want matrix inverses. (An existing use is getting the normal matrix for transformations. They can also be used to undo a transformation, although push() and pop() implementations can typically do this less expensively by storing matrices in a stack). A system solver is a direct generalization of the inverse feature and fits well with it.
  • [beginner-friendliness] Students are typically introduced to systems of linear equations well before they learn about trig, say, and that’s used a lot in p5.
  • [manageable implementation difficulty, depending on requirements?] Numerical linear algebra gets pretty involved, and implementing something as robust (performant, stable) as what MATLAB or Julia has would probably blow up the scope. (MATLAB provides a nice flowchart for selecting from among various algorithms and also provides a higher-level discussion of their features). But, we’ll probably at least want LU decomposition for matrix inverses anyway. And for a general linear-system solver including least squares, it might be enough to just add QR, if we just want something reasonably good for our use case. As long as our API is solid, add-ons could replace p5's implementation with something more sophisticated, right?

Follow-up considerations:

  1. [decompositions] For add-on libraries that want to use decompositions that may already be implemented in p5, like LU and QR, it’d be nice to expose them. That'd also be good for users who want to solve a bunch of systems with the same coefficient matrix. For a way of handling this that might not complicate the API too much, we might take some inspiration from MATLAB's decomposition objects. But, if this is too much of a complication for the public feature set, it seems like add-ons could still implement these things on top if they need to; I don’t think it’d be a lot of code, and it looks like we could make the API extensible enough.
  2. [special matrices] We might want to consider supporting a few special types of matrices like diagonal, triangular, and symmetric, at least internally, in order to choose better algorithms for those cases. My initial thought is that we could just have getter properties on the general matrix interface like isDiagonal, but there might be more to consider (e.g. special structure should also make it possible to reduce memory costs, and taking advantage of that seems more involved). Researching existing software and thinking through the best way to do this, and then exposing these features, might be beneficial. In addition to allowing special-purpose algorithms to be selected to improve performance, it'd create a model for add-ons to follow, in case they want to support other special types of matrices. I'm not sure if we'd want to add that much to the API, but I think "diagonal," "triangular," and "symmetric" are intuitive concepts, so it may not be a problem.
  3. [other solvers] If we have a linear system solver, we might ask whether we should also provide an iterative equation solver for solving single (linear or nonlinear) equations. I really haven't thought about this, but I suspect it’s better if we still relegate that kind of thing to other libraries.
Naming (general vs. graphics features) Assuming we end up having separate classes for general matrix features and specialized graphics features...

@davepagurek:

For naming, I'm currently thinking the graphics-specific one could be called something like TransformationMatrix?

I like "TransformationMatrix"! It’ll be familiar to users, and it’s accurate: mathematically, a "transformation matrix" can represent linear, affine, and projective transformations, all of which p5 uses. In fact, the Wikipedia article of the same name covers all three. I don't think it's too general or vague either: although all of p5’s matrices could be thought of as transformations, I think the graphics versions are the only ones we’d refer to as transformations in the reference, and the only ones that are intentionally interpreted as transformations.

The name is a little long, but I’m not too worried about that; it's probably better to avoid abbreviations, and that'd be consistent with other p5 names like p5.Vector (not p5.Vec) etc. We could consider TransformMatrix, but I think "transform matrix" is much less common. The standard term in this context seems to be "transformation matrix" (CSS has a "transformation matrix" that accumulates "transforms", three.js uses this terminology in its docs, the MDN reference on DOMMatrix uses similar terminology, etc.)

A shorter alternative that doesn't rely on abbreviations is GraphicsMatrix, but that's not as precise or standard, so it's less predictable. It also doesn't have any special relation to p5.Graphics, as the name might suggest. So I still prefer TransformationMatrix.

Basic vs. augmented matrices When I mentioned "linear" vs. "affine," I had a somewhat different idea in mind. I'll try to explain it here for anyone following along. Since "affine" will be unfamiliar to most p5 users, I'll also discuss simpler terminology at the end.

We can represent any linear transformation from $ℝ^n$ to $ℝ^n$ as an $n \times n$ matrix $A$, or we can represent that same transformation as a special case of an affine transformation, using an $(n+1) \times (n+1)$ augmented matrix that also allows for translations (which are nonlinear):

To represent a linear transformation like a rotation, we can let the translation vector b equal the zero vector. In general, the matrix A and the corresponding augmented matrix when $n = 2$ look like this:

(The components of $\textbf{b}$ are labeled using "t" for translation vector. This is pulled from MDN.)

Now, if I talk to a linear algebra student about rotation matrices, they're going to think of the $n\times n$ matrix $A$ (Cartesian coordinates), but graphics programmers may think of the $(n+1) \times (n+1)$ augmented matrix (homogeneous coordinates). So, we might want to support both versions:

  • [basic] The matrix $A$ is simpler and is a good building-block for leading up to an explanation of the augmented matrix.
  • [augmented] The augmented matrix has the advantage that it allows for affine transformations (like translations) and projective transformations (like perspective projections).

I was thinking there could be dedicated methods for creating both of types of matrices via the “graphics”/"transformation matrix" interface. The user would just supply an angle, and if appropriate, an axis. They'd also need to specify the dimension in some way (e.g. with a mode, a method argument, or a dedicated method). Although @davepagurek mentioned supporting just $3 \times 3$ and $4 \times 4$ under that interface, this would mean supporting $2 \times 2$ as well for the graphics features. (That'd be similar to three.js, which has separate classes for $n$ = 2, 3, and 4, but I guess we'd still have these all in one class, for consistency with p5.Vector and p5.Matrix).

If we support both the basic and augmented transformations on a p5.TransformationMatrix class, we could distinguish them with some kind of name (maybe a mode parameter name or a method-naming convention). Since all the transformations—linear, affine, and projective—have augmented versions, maybe those could be the default interpretation. The linear transformations, including rotation, scaling, and any others we add, could maybe have additional, “basic” versions, like setBasicRotation() and setBasicScaling()? We could also try synonyms like “simple,” if we want to be consistent with e.g. the new “simple” and “full” stroke modes.

But, I think the first thing is to decide whether we want the "basic" versions at all. We could consider what other libraries do, but I think that for p5, supporting both might make sense? Another option would be to support only the augmented versions, since it'd still be possible to implement the basic versions by setting matrices manually via p5.Matrix's general setters.

Design

Documenting design challenges

@holomorfo:
I would like to continue this effort or collaborate with whoever might be working on it since its really tricky to do the modifications while not breaking existing functionality and maybe I can provide some insight.

Glad you’re going to continue with this! Do you think you might be able to summarize with bullet points why it’s tricky to change things without breaking them? Those pain points might either suggest opportunities for improvement, or if not, they might give us a better sense of the design constraints. A list of examples, or if it’s easier, some general types of challenges, would probably be really helpful.

Overall design

How might we separate general and graphics features, at a high level? How might we want shared features to be shared? What design patterns make sense? Would CRC cards be helpful here?

So far, we've discussed having separate p5.Matrix and p5.TransformationMatrix classes, with some kind of shared interface. I think the current idea is to use an abstract class to implement that interface, i.e. MatrixInterface. One very preliminary idea we might consider is whether some kind of composition might be desirable. For example, if we have high performance implementations for small transformation matrices, it'd be great to use those implementations in the general matrix class when possible. I suppose that might complicate things by introducing a class dependency, but maybe the general class could fall back to a general implementation if the specialized one is unavailable. This would mean users could benefit from the higher performance even if we decide to keep p5.TransformationMatrix private, which might make sense if we want to keep the API small.

Phasing/hiding

Assuming we separate the general and graphics features into different classes, would it make sense to expose the general matrix class first? Would we definitely want to expose the performant graphics version later?

My initial thinking is that it would still make sense to expose both, although possibly in stages to be a little safer. Exposing the graphics version would force us to clean it up and make things better for contributors, it'd help p5 users advance and learn more about graphics, and it’d probably make it easier for add-on contributors to reuse the same functionality (e.g. maybe they want to allow transforms inside custom coordinate systems, or if they're working on an animation feature, they might want to repeatedly apply graphics transformations to an individual shape rather than the entire coordinate system...). But, as noted above, it wouldn't be quite as important to expose both classes if p5.Matrix delegates to p5.TransformationMatrix for performance gains when possible (in that case, I guess the graphics class would mainly provide convenience functions).

If the general and graphics interfaces are well designed, I think there will be a clear enough logical separation for users, and their interfaces will be similar enough that learning one will make it easy to learn the other.

Edit: Revised comment regarding matrix inverses.

@ksen0
Copy link
Member Author

ksen0 commented Apr 23, 2025

Hi @Mamatha1718 thanks for your interest, but as you mentioned, there is still a lot of discussion ongoing, so it might make sense to check back in later/periodically or look for issues that are marked ready for work if you're interested in getting started with implementation.

Thanks for all the rigorous discussion @holomorfo @GregStanton @davepagurek ! Here's a proposed breakdown of implementation steps that I feel are still consistent with the intent and leave some room for discussion:

  1. Factor out TransformationMatrix (lives in Transform) which should subclass Matrix (lives in Math) - I don't have a strong opinion on where these classes are in terms of file structure, but after some discussion yesterday with @davepagurek and @limzykenneth, I believe it would be helpful to keep these clearly distinct in docs. In this step, both classes stay private.
  2. Expose the graphics-specific TransformationMatrix (or other name as needed) with as few functions made public as reasonably possible. This might benefit form slight revision/clarification in the documentation wording. The result of this step would be merged into the next minor release as it's a bigger additive update.
  3. Work on a generic implementation of the didactic nxm matrices that is still compatible and render performant and possibly subject to new guidelines like modification in place or copy a new object. This step is independent of step 2, and can be worked on in parallel - and will probably take a little longer, since this is the most open to discussion topic.

I think each of these are separate PRs / possibly separate issues. Importantly, I think both 1 and 2 are well-defined given what's already there, but 3 is a major topic, so I think it would be productive to keep that one a bit separated. I'm assigning this issue to @holomorfo for clarity, but of course the discussion and work can be distributed!

@GregStanton noted:

Assuming we separate the general and graphics features into different classes, would it make sense to expose the general matrix class first? Would we definitely want to expose the performant graphics version later?

My 2 cents here is that exposing the graphics matrix first is strongly preferable because that is the primary current use-case, there's a lot of performance work that's been done, and the main things preventing TransformationMatrix from being exposed are relatively minor - whereas there is substantial design discussion and implementation and performance work that seems to be needed for the didactic Matrix. My suggestion would be to always unblock: if something is almost ready, then it's a good idea to get it ready first, rather than opening a whole new topic. In any case, the overall intent here is still to expose a general-purpose p5.Matrix, just a comment on order of implementation.

@Mamatha1718
Copy link

@ksen0 , Thanks for the clarification! I understand that things are still evolving. I’ll keep an eye on the discussions and look out for issues marked “ready for work.”

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Open for Discussion
Development

No branches or pull requests

5 participants