Skip to content

[RFC]: integrate stdlib into scijs packages #230

@Aniket-SS

Description

@Aniket-SS

Full name

Aniket Sanjay Sonawane

University status

Yes

University name

Atal Bihari Vajpayee Indian Institute of Information Technology and Management, Gwalior (ABV-IIITM)

University program

Integrated post-graduate in masters of business administration (IPG-MBA)

Expected graduation

2027

Short biography

I am a pre-final year student pursuing a dual degree in B.Tech in IT+MBA. After learning tech for 3 years in college, currently my studies revolve around various managerial domains like finance, operations, HR and marketing.

I’ve been maintaining strong academic performance since the beginning of my schooling where my coding journey began. During my initial college days, I got to know about web applications and databases from my peers. Out of curiosity, I too started learning web development and that marked the beginning of my journey in tech. After taking part in hackathons and coding contests it was time I wanted to explore a new domain which brought me to the world of open source.

Beyond academics, I am passionate about developing applications and exploring emerging technologies. My journey began with web development, subsequently expanding to full-stack, comprising both frontend and backend development. I have experience with JavaScript, Node.js, C/C++ and python. I used React for frontend and also had MATLAB for one of my labs in college.

I have a strong affection for mathematics and I love to solve math problems and puzzles in my free time so whenever I get bored my one stop would be playing on Matiks - a platform for Mental Math Duels and Puzzle Battles.

Timezone

Indian Standard Time (UTC +5:30)

Contact details

email: sonawaneaniket7@gmail.com, github: Aniket-SS

Platform

Windows

Editor

I use Visual Studio Code not just because it is lightweight, fast, has great support for multiple languages or its user-friendly interface but mainly because I am used to it now. The built-in Git integration and support for a wide variety of available extensions enhance my workflow ensuring consistent code quality and faster development.

Paired with Windows Subsystem for Linux (WSL), it allows me to run a Linux environment seamlessly on my Windows machine making development more efficient.

Programming experience

My programming journey began in school where I learned languages like C, basics of Java and also concepts of OOPs. Later I delved deeper into coding during college, expanding my knowledge of HTML, CSS and JavaScript through web development. I explored backend technologies, specifically the MERN stack (MongoDB, Express.js, ReactJS, Node.js) along with databases (PostgreSQL) and shell scripting.

Here are some notable projects I built during my programming journey:

  • Library Application - built a library app integrating Google Books API for retrieving book metadata and Open Library Covers API for displaying book covers. Added features to manage notes, ratings and track the reading of users.
  • Family Travel Tracker - developed a web application to track family travel plans and to mark the countries visited using the Google Earth map integration. Implemented user authentication, dynamic forms, and a responsive design.

Till date I worked on various projects, participated in various hackathons and coding contests. Currently, I am strengthening my foundation in Data Structures and Algorithms and their space and time complexities as it is a prerequisite for college placements at many tech companies.

JavaScript experience

JavaScript is the language I am most comfortable with as I've been using it as my main programming language for quite some time now. I’ve used it in my personal projects and working with JavaScript has allowed me to explore its versatility, from building backend services and APIs to designing rich frontend interfaces.

JavaScript is a single threaded language which is similar to how the human brain or body can process one task at a time in real life yet can context-switch between tasks or even can delegate tasks. It can achieve the same by using asynchronous functions like setTimeout(), fs.readFile(), fetch(). What I really like about JavaScript is that its asynchronous nature allows it to handle multiple tasks without pausing execution making it ideal for handling user interactions, API calls and real-time events.

One of JavaScript’s biggest advantages is its rich ecosystem, which includes a wide range of frameworks and libraries for frontend development like React. It can also be used for backend development. It is a dynamic language so it can move faster and does not have more strict code like other languages.

JavaScript is often criticized as unsuitable for large scalable systems because of its single threaded nature. However, there is a way to make it use all cores of your machine by doing things in parallel and the overall time to complete a task can be reduced by delegating and context switching.

Node.js experience

My experience with Node.js comes from building backend services, developing APIs for my projects and performing general-purpose scripting. I've hands-on experience with various frameworks and libraries such as Express.js.

I’ve primarily used Node.js to set up servers and REST APIs. I've built a couple of full-stack projects using Node.js with Express.js where I designed and implemented both the backend and frontend. The projects involved handling user authentication, managing database connections and exposing various endpoints.

C/Fortran experience

The first language I learned in programming was C back in my school days, where I built basic programs. I’ve now gained experience in working with C/C++ by solving Data Structure and Algorithms problems on coding platforms like LeetCode, GeeksforGeeks and Codeforces.

Although I don’t have any experience with Fortran, I will be happy to learn if needed.

Interest in stdlib

At the start of 2026, while searching for participating organizations in GSoC I came across stdlib. Due to my background in engineering and interest in numbers, I was immediately interested in stdlib. I came across a session titled ‘Introduction to stdlib-js’ by @Planeshifter in International Javascript Conference(iJS) which helped me gain a deeper understanding of stdlib’s mission and I was amazed to see its potential impact. Hence, of all the interested organizations I was listing in my excel for GSoC, I decided to begin my open-source journey with stdlib, setting aside the other organizations.

One feature I find particularly exciting about stdlib is its extensive collection of mathematical and statistical functions and the work that is being done to bring numerical and scientific computing to the web. I’ve always wondered how they are actually implemented and stdlib provided me with a platform where I could see and experience that firsthand, and on top of it, even contribute to it.

On a personal level, stdlib holds a special place for me as my first ever open-source contribution. I was really excited when my first PR #10701 got merged and I haven’t looked back since then. When I went through the codebase I recognized many distributions I had previously heard of or studied actually implemented in stdlib.

The stdlib repo is highly stable and well-maintained, with the perfect contribution guide so that new contributors do not feel overwhelmed by looking at such a large codebase for the first time. I like how structured the repo is with every package having tests and benchmarks. The detailed review process and strong emphasis on maintaining a high-quality codebase have helped me improve my skills and appreciate the importance of writing clean, consistent code.

What makes stdlib truly special is its welcoming and supportive community. The maintainers are approachable and always ready to guide contributors both on GitHub and Zulip chat, making it easy for newcomers to get started. The weekly Office Hours meetings help contributors resolve blockers and questions. Being part of such a positive and inspiring community motivates me to continue contributing and growing as a developer.

Version control

Yes

Contributions to stdlib

Merged PRs

Open PRs

Issues

A comprehensive list of all my pull requests can be found here:

…and several more

Additionally I keep revisiting our codebase to find any gaps in documentation, examples and other errors that may have been missed during review. Recently I have also begun systematically resolving open doable TODOs and FIXMEs present in our codebase.

stdlib showcase

Live demo

GitHub link

A stdlib showcase project demonstrating the capabilities of stdlib, with a focus on ndarray operations and mathematical functions. I built an interactive web application bundled with webpack and deployed on GitHub Pages that uses stdlib for all its computation. The project has three functional demonstrations:

The user specifies an arbitrary shape, chooses a fill mode and the app creates a stdlib ndarray using ndarray/array, renders it as a visual grid with highlighted cells and displays the computed strides using ndarray/strides alongside the data. A Slice Explorer accepts start:stop notation for row and column axes and calls ndarray/slice to produce the subview highlighting the sliced cells in the grid. An element-wise operations panel applies square, negate, and absolute value transforms using ndarray/base/unary updating the grid in place.

An editable grid lets the user input two vectors or matrices, compute their dot product via blas/base/ddot and perform full matrix multiplication, with the result displayed as a rendered matrix. The Frobenius norm of the result is computed using math/base/special/sqrt over the sum of squared entries. Matrix size is selectable between 2×2, 3×3, and 4×4.

Historical OHLCV data is parsed from a CSV file into a stdlib ndarray. Summary statistics like average close price, 6-month high, 6-month low, annualized volatility and average daily return are computed using stats/base/dmean, stats/base/dvariance, stats/base/max, stats/base/min and math/base/special/sqrt. Three interactive canvas charts display close prices with a configurable rolling moving average (MA) (5/10/20-day window), daily returns and trading volume.

This project served as a hands-on exploration of stdlib's numerical capabilities and deepened my understanding of the codebase I aim to contribute to through GSoC.

Goals

The goal of this idea is to integrate stdlib into scijs packages and to implement scijs operations in stdlib which are not currently present. The work will include updating various scijs packages to accept and operate on stdlib ndarrays, and where stdlib equivalents already exist, updating the current scijs implementations to delegate to stdlib implementations. By delegating such utilities and updating existing scijs packages to operate on stdlib will help achieve a complete javascript ecosystem.

Background:

scijs is a collection of numerical and scientific computing packages and utilities for working with multi-dimensional array data. It is not a single library, but rather an ecosystem of highly modular, independent modules each focusing on specific numerical tasks. A key point of friction within the JavaScript ecosystem is the lack of interoperability between stdlib and scijs.

Core Problem:

A scijs ndarray exposes properties .stride (singular), .dimension, while a stdlib ndarray uses .strides (plural), .ndims, and an explicit .order field. There is currently no common interface between them, which means any package from scijs that receives a stdlib ndarray will silently break and any stdlib function called internally within a scijs package needs manual wrapping to handle the structural mismatch. This project resolves that incompatibility at every layer.

Beyond the ndarray interface mismatch, there is a second systemic issue affecting scijs's usability in modern browser environments.

Other Problem:

cwise is the code generation library currently powering much of scijs's element-wise operations and has a known CSP incompatibility in browser environments because it generates and evaluates code at runtime. cwise generates code strings and evaluates them at runtime via new Function(), which has long been flagged as a CSP violation in browser environments that disable unsafe-eval.

"use strict"

var transform = require("./lib/cwise-transform.js")
var base = require("./lib/cwise-esprima.js")

module.exports = function(a, b) {
  if(typeof a === "string") {
    return transform(a, b)
  } else if(typeof a === "object") {
    return base(a)
  } else {
    throw new Error("cwise: Invalid arguments")
  }
}

cwise, cwise-compiler, and cwise-parser are not three separate tools but are one single pipeline:

Note

cwise (API) → cwise-parser (esprima) → cwise-compiler (code gen) → runtime eval/new Function() (the CSP violation)

  • cwise-parser uses esprima to parse the function body passed to cwise into an AST
  • cwise-compiler takes that AST and generates optimized loop code as a string
  • cwise calls both and then executes the generated string via new Function() at runtime

It affects any scijs package that depends on cwise: (@scijs/ndarray/fill, @scijs/ndarray-pack, @scijs/ndarray-unpack, @scijs/ndarray-ops, @scijs/ndarray-complex, @scijs/ndarray-stencil, @scijs/ndarray-gradient, etc) when deployed in security-hardened browser contexts. The stdlib ecosystem avoids this pattern entirely.

Main Goal:

The main goal of this project is to establish a clean integration between scijs and stdlib so that the two ecosystems can interoperate seamlessly. At present, despite operating in the same space of numerical computing in JavaScript, the two cannot work together primarily because their ndarray representations are structurally incompatible.

Supporting Goals:

  • Enhance the overall interoperability and browser compatibility of all mentioned scijs packages by establishing a clean delegation path to stdlib and eliminating cwise-based runtime code generation.
  • Ensure all new implementations are thoroughly tested with relevant benchmarks, unit tests achieving 100% test coverage for all packages.
  • Update documentation for all modified and newly implemented packages to maintain clarity, usability and alignment with stdlib’s conventions.
  • Provide detailed documentation and usage guides for all updated packages to help users understand their functionality

Approach:

Based on my analysis of 41 scijs packages and discussions with the maintainers, I've identified four concrete technical goals:

1. Establish an interoperability layer via adapter packages:

Adapter packages (@stdlib/ndarray/to-scijs, @stdlib/ndarray/from-scijs) will live as standalone repositories on the stdlib-js GitHub org and will be published under the stdlib npm org. These will expose utilities to convert in both directions which is a scijs ndarray to a stdlib ndarray and vice versa. At the entry point of every updated scijs package, a ndarray/to-scijs utility will be used to accept stdlib ndarrays from users without requiring them to convert manually.

2. Update scijs packages that don't depend on cwise to normalize inputs and outputs:

For packages that do not depend on cwise (@scijs/ndarray-squeeze, @scijs/ndarray-unsqueeze, @scijs/ndarray-blas-level1, @scijs/ndarray-blas-level2, etc), stdlib equivalents can be called directly once inputs are normalized. However, when such a package returns an ndarray, the return value must be converted back to a stdlib ndarray if the input was a stdlib ndarray so that the "brand" of the output must match the brand of the input. This requires a hard stdlib dependency in those packages and careful attention to bundle size at every step.

3. Replace cwise-based implementations with stdlib equivalents:

For packages that depend on cwise (@scijs/ndarray-fill, @scijs/ndarray-pack, @scijs/ndarray-unpack, @scijs/ndarray-ops), the approach is to normalize to a stdlib ndarray, call the stdlib operation, and convert the result back to an ndarray. The scijs package becomes a thin wrapper over stdlib. A hard stdlib dependency is unavoidable here and it eliminates cwise's longstanding CSP violations in browser environments.

4. Implement missing stdlib primitives and have scijs delegate to them:

Several scijs packages (@scijs/ndarray-trace, @scijs/ndarray-determinant, @scijs/sphere-random), FFT (@scijs/ndarray-fft) and (@scijs/ndarray-band, @scijs/ndarray-tile, @scijs/ndarray-stencil, @scijs/ndarray-gradient) have no stdlib equivalent yet. For these, I will implement the missing stdlib functions first and then have the scijs packages delegate to them.

The Bridge Architecture:

These two utilities, once established and reviewed, become the reusable foundation for every subsequent phase.

  1. @stdlib/ndarray/from-scijs (internal):
    It is used inside scijs packages when calling a stdlib function. It handles property mapping (.stride.strides, .dimension.ndims) and infers the .order field from stride values since scijs does not store it explicitly.
'use strict';

var ndarray = require('@stdlib/ndarray-ctor');

function scijsToStdlib(arr) {
    var dtype   = arr.dtype || 'generic';
    var buffer  = arr.data;
    var shape   = arr.shape;
    var strides = arr.stride;   
    var offset  = arr.offset;
    var order   = inferOrder(strides);

    return new ndarray(dtype, buffer, shape, strides, offset, order);
}

function inferOrder(strides) {
    var n = strides.length;
    if (n <= 1) {
        return 'row-major';
    }
    var absFirst = Math.abs(strides[0]);
    var absLast  = Math.abs(strides[n - 1]);
   
    return (absLast <= absFirst) ? 'row-major' : 'column-major';
}

module.exports = scijsToStdlib;
  1. @stdlib/ndarray/to-scijs:
    It is used at the entry point of each updated scijs package. It accepts either a scijs ndarray or a stdlib ndarray and returns a normalized stdlib ndarray for internal use. This is user-facing in the sense that it determines what inputs the package accepts.
'use strict';

var ndarray = require('ndarray');

function toScijs(arr) {
    return ndarray(
        arr.data,
        arr.shape,
        arr.strides, 
        arr.offset
    );
}

module.exports = toScijs;

Entry point pattern:

It is used at the top of every updated scijs package:

'use strict';

var fromScijs = require( '@stdlib/ndarray/from-scijs' );
var toScijs   = require( '@stdlib/ndarray/to-scijs' );

function normalizeInput( arr ) {
    
    var isStdlib = ( arr.strides !== void 0 && arr.ndims !== void 0 );
    return {
        normalized: isStdlib ? arr : fromScijs( arr ),
        wasStdlib:  isStdlib
    };
}

function restoreBrand( result, wasStdlib ) {
   
    return wasStdlib ? result : toScijs( result );
}

Package Classification:

I went through every scijs repository one by one reading the source, tracing how ndarrays are created and passed through each function, checking where cwise is called and whether stdlib has a matching routine. That research ended up producing the package-by-package breakdown across 41 packages that forms the backbone of this proposal.

1. Priority: high

  • Clean Delegate: isndarray, ndarray-concat-rows, ndarray-concat-cols, ndarray-gemm, zeros, gauss-random → 6
  • Wrap / Adapter: ndarray-fill, ndarray-pack, ndarray-unpack → 3
  • Partial Delegate: ndarray-ops, ndarray-squeeze, ndarray-unsqueeze, ndarray-linspace, ndarray-normalize, ndarray-sort, ndarray-householder-qr, ndarray-distance, ndarray-moments → 9

2. Priority: medium

  • Implement then delegate / wrap: ndarray-linear-solve, ndarray-trace, ndarray-fft, ndarray-determinant, sphere-random, ndarray-lup-factorisation, ndarray-lup-solve → 7
  • BLAS Extraction: ndarray-blas-level1, ndarray-blas-level2, ndarray-blas-gemv, ndarray-blas-dger, ndarray-blas-trsv → 5
  • Derived: ndarray-diagonal → 1

3. Priority: low

  • Implement new APIs: ndarray-band, ndarray-tile, ndarray-stencil, ndarray-gradient, ndarray-select, ndarray-linear-interpolate → 6
  • Cannot Delegate: ndarray-bit, ndarray-string, ndarray-hash, ndarray-complex→ 4

Breakdown of Packages according to their integration type: Google sheet

A detailed reference document cataloguing the arguments, return values, and operational behavior for all 41 scijs packages has been compiled and is available here to guide precise implementation decisions during the coding period.

Type 1: Clean Delegate (6 packages)

stdlib equivalent exists and covers all cases. No adaptation needed.

Package What it does stdlib equivalent cwise? Returns ndarray?
isndarray Checks if argument is an ndarray @stdlib/assert/is-ndarray-like
ndarray-concat-rows Concatenates ndarrays along first dimension @stdlib/ndarray/concat
ndarray-concat-cols Concatenates ndarrays along last dimension @stdlib/ndarray/concat
ndarray-gemm Generalized matrix multiplication @stdlib/blas/base/dgemm
zeros Creates ndarray initialized to zero @stdlib/ndarray/zeros
gauss-random Samples from unit Gaussian distribution @stdlib/random/base/randn

Type 2: Wrap / Adapter (3 packages)

cwise-dependent. Input normalized, callback adapted, stdlib called, output brand restored.

Package What it does stdlib equivalent cwise? Returns ndarray?
ndarray-fill Fills ndarray via index-coordinate callback @stdlib/ndarray/fill-by
ndarray-pack Converts nested array to packed ndarray @stdlib/ndarray/array
ndarray-unpack Converts ndarray to array-of-arrays @stdlib/ndarray/to-array

Type 3: Partial Delegate (9 packages)

stdlib equivalent exists but does not cover all cases. Requires input normalization and careful output handling.

Package What it does stdlib equivalent cwise? Returns ndarray?
ndarray-ops Collection of element-wise math operations @stdlib/ndarray/base/unary, binary
ndarray-squeeze Removes singleton dimensions @stdlib/ndarray/base/remove-singleton-dimensions
ndarray-unsqueeze Inserts singleton dimension @stdlib/ndarray/base/expand-dimensions
ndarray-linspace Fills ndarray with equally spaced values @stdlib/array/linspace, @stdlib/blas/ext/base/ndarray/dlinspace
ndarray-normalize Normalizes ndarray so that mean=0, std=1 @stdlib/stats/array/mean + stdev + @stdlib/ndarray/unary
ndarray-sort Sorts ndarray in place along first axis @stdlib/blas/ext/sorthp
ndarray-householder-qr QR factorization via Householder reflections @stdlib/lapack/base (dgeqrf, dorm2r, dorg2r, dtrtrs)
ndarray-distance Computes Lp distance between two ndarrays @stdlib/blas/ext/base (norms)
ndarray-moments Computes first n statistical moments @stdlib/stats/base (mean, variance, etc.)

Type 4: Implement then Delegate (7 packages)

No stdlib equivalent yet. Missing primitive must be implemented in stdlib first, then scijs delegates to it.

Package What it does stdlib primitive to implement cwise? Returns ndarray?
ndarray-linear-solve Solves linear system AX = B @stdlib/lapack/base/dgetrf + dgetrs
ndarray-trace Sum of all diagonal entries @stdlib/ndarray/trace (new)
ndarray-fft Fast Fourier Transform on complex array @stdlib/fft/base/fftpack (PR in progress)
ndarray-determinant Determinant of a square matrix det via LU from @stdlib/lapack/base/dgetrf
sphere-random Random point on d-dimensional hypersphere @stdlib/random/base/sphere (new)
ndarray-lup-factorisation LUP factorization of matrix @stdlib/lapack/base/dgetrf
ndarray-lup-solve Solves using precomputed LUP factors @stdlib/lapack/base/dgetrf

Type 5: BLAS Extraction (5 packages)

Wrap BLAS routines. stdlib BLAS takes (N, data, stride, offset) as separate arguments hence ndarray fields must be extracted explicitly.

Package What it does stdlib equivalent cwise? Returns ndarray?
ndarray-blas-level1 Basic vector operations (BLAS Level 1) @stdlib/blas/base/ (ddot, daxpy, dnrm2…) ✗ / ✓
ndarray-blas-level2 Matrix-vector operations (BLAS Level 2) @stdlib/blas/base (dgemv, dtrmv, dtrsv, etc.)
ndarray-blas-gemv Matrix-vector multiply for ndarrays @stdlib/blas/base/dgemv
ndarray-blas-dger BLAS Level 2 DGER for ndarrays @stdlib/blas/base/dger
ndarray-blas-trsv Triangular solve for ndarrays @stdlib/blas/base/dtrsv

Type 6: Derived (1 package)

Output is a view derived from the input ndarray; no independent computation.

Package What it does stdlib equivalent cwise? Returns ndarray?
ndarray-diagonal Returns a view of diagonal entries @stdlib/ndarray/ctor (stride = stride[0]+stride[1])

Type 7: Implement New APIs (6 packages)

No equivalent in stdlib or scijs. New stdlib packages must be designed and implemented from scratch.

Package What it does stdlib package to create cwise? Returns ndarray?
ndarray-band View of a band of an ndarray @stdlib/ndarray/band
ndarray-tile Tiles ndarray according to reps per dimension @stdlib/ndarray/tile
ndarray-stencil Creates a stencil operator for ndarray @stdlib/ndarray/stencil
ndarray-gradient Computes gradient with boundary conditions @stdlib/ndarray/gradient
ndarray-select Selects kth element along first axis @stdlib/ndarray/select
ndarray-linear-interpolate Multilinear interpolation on ndarray @stdlib/ndarray/interpolate

Type 8: Cannot Delegate (4 packages)

Structurally incompatible with stdlib's ndarray model. Explicitly excluded after full analysis.

Package What it does Reason for exclusion
ndarray-bit 1-bit-per-element ndarray stdlib minimum dtype is uint8; 1-bit storage is structurally incompatible
ndarray-string Unicode codepoint ndarray view of a string stdlib has no string dtype or codepoint ndarray concept
ndarray-hash Sparse ndarray backed by a hash map stdlib ndarrays are always dense, typed-array backed; no sparse equivalent
ndarray-complex Complex ops using separate real/imag ndarrays Deep argument layout mismatch with stdlib's native complex64/complex128; (Needs discussion with mentor)

Dependency Sequencing

Some packages cannot be completed until missing stdlib primitives land first. I've mapped these blocking relationships explicitly so that the work is sequenced correctly:

  • ndarray-householder-qr depends on lapack/base/dgeqrf (not yet merged) and lapack/base/dtrtrs (does not exist yet). Both must land before qr.solve() can be delegated.
  • ndarray-lup-factorisation and ndarray-lup-solve both block on lapack/base/dgetrf which is not yet in stdlib.
  • ndarray-fft blocks on the in-progress FFT PR.

If that PR merges during the coding period, ndarray-fft becomes a straightforward delegate and is included in the deliverables. If it does not land in time, ndarray-fft is treated as a stretch goal and explicitly excluded from the core timeline so it does not create schedule risk for the higher-priority packages.

In each case, implementing the missing stdlib primitive is the first deliverable, and the scijs wrapper follows immediately after. This sequencing is already reflected in how I've ordered the phases below.

For ndarray-householder-qr, dorm2r and dorg2r are yet to be merged:

  • #7797 feat: add lapack/base/dorm2r
  • #7784 feat: add lapack/base/dorg2r

Development Workflow:

As discussed with the maintainers, all development will happen on forks of scijs repos hosted on the stdlib-js GitHub org. Pull requests to the actual scijs GitHub org will only be opened after implementations have been finalized and reviewed to avoid introducing churn and imposing unnecessary burdens for the broader scijs community.

Why this project?

stdlib and scijs are both collections of libraries for numerical and scientific computing in JavaScript, but they differ in their scope, architecture and design philosophy. What excites me most about this project is the chance to bridge the gap between these two which will improve the usability and adoption of stdlib ndarrays, making numerical computing more accessible in JavaScript.

When going through all the project ideas available for GSoC, I came across this idea’s description which had working with multi-dimensional array data mentioned in it. Having already been contributing to stdlib, this project stood out immediately as it directly addresses a problem and aligns with my interests.

Other factors I considered before selecting this project were:

  • It is a high-priority project in stdlib and I wanted to make some meaningful contributions to the community.
  • The tech required for the completion of this project is JavaScript and Node.js, which I am most comfortable working with.
  • The difficulty level of this project is 3 which I consider to be both challenging and rewarding for a newcomer like me to the world of open source.

The value stdlib offers its users will undoubtedly increase once we have these routines and I would love to be a part of this effort. By contributing to this project, I aim to deepen my understanding of ndarray structures and statistical operations while making meaningful contributions to the open-source community. The challenge of designing efficient, modular solutions that align with stdlib's mission to make high-performance numerical computing accessible in JavaScript is both inspiring and rewarding.

Beyond that, this project has real consequences. Replacing cwise eliminates a long-standing CSP issue in browser environments. Establishing interoperability between the two ecosystems means that users no longer have to choose between them. Getting this right with proper testing and reviewing will have lasting value for the JavaScript scientific computing community.

The proposed project offers an exciting opportunity to learn something new and that is why I'm excited to take on this project.

Qualifications

When I started contributing to stdlib and went through the GSoC project ideas list, the scijs integration project was the one I immediately wanted to understand deeply, not just at the proposal level but at the implementation level. So before writing a single line of this proposal, I spent hours going through every scijs repository one by one reading source files, dependencies, tracing how ndarrays flow through each package, finding where cwise is called, checking what stdlib already provides and cataloguing what is missing.

I have been actively contributing to stdlib and that work has given me direct experience with the parts of the codebase most relevant to this project. I have familiarized myself with the code structure and conventions followed in stdlib repository by going through documentation making me well-prepared to contribute to stdlib. Since the start of 2026, I have focused on contributing to stdlib by addressing good first issues and getting myself aware of the convention and structure followed. I’ve authored PRs for adding packages, which has prepared me for larger tasks and a strong candidate to work on this project.

POC implementation and results:

To validate my integration approach before writing this proposal, I implemented a proof-of-concept for ndarray-fill locally which is one of the cwise-dependent packages. The POC includes a ndarray/from-scijs bridge that maps scijs ndarray properties (.stride → .strides, .dimension → .ndims) and infers the .order field from stride values, as scijs ndarrays do not store it explicitly. With the bridge in place, ndarray-fill delegates to @stdlib/ndarray/fill-by internally and the output ndarray is reconstructed with the same brand as the input.

The POC passes both the existing scijs test suite without modification and an extended test suite covering 1D/3D arrays, typed array buffers, non-zero offsets and brand preservation which confirms that the bridge approach preserves backward compatibility.

Academic background:

Outside stdlib, matrices have played a significant role in my academic studies. In my first college year, I spent an entire semester studying matrices and their operations, giving me a strong academic background, mathematical foundation and the ability to handle complex problems in this project. (e.g. - finding rank, elementary transformations, inverse through Gauss Jordan, eigen values and eigen vectors, etc.) and I believe this background will come in handy in the implementation of this project.

I am also going through this book - Introduction to Numerical Methods with examples in javascript to strengthen my theoretical foundation for this project.

I am confident I'm well-qualified to undertake this project over the coming summer after having several ongoing discussions about the project with stdlib maintainers on Zulip chat where I've been clarifying implementation details and aligning my approach with the project's goals.

Prior art

There has been no previous structured effort to integrate scijs and stdlib. The two ecosystems have grown in parallel within the same JavaScript scientific computing space, each independently building its own ndarray foundation. As a result, packages from one ecosystem cannot accept inputs from the other, even though their underlying operations are equivalent.

The closest conceptual analogy in another language is the relationship between NumPy and SciPy in Python. NumPy defines the array type; SciPy builds on it instead of reimplementing the same operations.

This project brings that same design logic to the JavaScript numerical computing space: stdlib provides the primitives and scijs packages become thin, well-tested wrappers that delegate to them. For this project, I've already completed the upfront analytical work: going through 41 scijs packages, classifying each one by integration type, stdlib equivalent, whether cwise is present, whether the package returns an ndarray and the dependency relationships between packages.

The prototype for the bridge adapter handling the .stride.strides, .dimension.ndims property mapping and inferring .order from stride values is documented in above sections. It includes two packages that transforms a scijs ndarray into stdlib ndarray via ndarray/from-scijs and inversely stdlib ndarray back to scijs ndarray through ndarray/to-scijs. Having thoroughly understood the differences between stdlib and scijs, I have defined a clear implementation blueprint for this project.

My research also surfaced three non-trivial integration challenges that require careful handling:

  • A ndarray/to-scijs wrapper is not sufficient on its own i.e. when a scijs package returns an ndarray, the return value must carry the same brand as the input (a user passing in a stdlib ndarray should get a stdlib ndarray back, not a scijs one).
  • When a package depends on cwise, you cannot simply swap the internal call without restructuring how element-wise callbacks are passed.
  • When the package is a BLAS wrapper, stdlib's (N, data, stride, offset) argument layout means you cannot pass the ndarray object at all and have to extract its fields explicitly.

This groundwork will serve as a valuable resource for me as I work on the project.

References: the scijs package listing, the scijs GitHub organization, the stdlib repository

Commitment

I am applying for the 350-hour (full-time equivalent) project size and plan to dedicate 30–35 hours per week throughout the GSoC period. My university end-semester examination is from 27th April-3rd May which is during the community bonding period (May 1-24). So the examination ends well before the coding period begins, so I will be fully available from 3rd May onwards. I do not have any internship or travel commitment after 3rd May that would reduce my availability or interrupt my work.

I have been contributing to stdlib consistently so the development workflow, PR format, test conventions and documentation standards are already familiar to me.

Schedule

Priority order:
Clean Delegate → Wrap/Adapter → Partial Delegate → BLAS → Derived → Implement-first → Cannot Delegate

  1. Clean delegates establish the bridge and prove the interoperability pattern.
  2. Adapter packages (the cwise replacements) come next because they build on the same normalized bridge.
  3. Partial delegates combine stdlib calls with custom logic.
  4. BLAS packages have a distinct extraction pattern and need their own phase.
  5. implement-first packages are last because they require new stdlib primitives

Community Bonding Period (Weeks 1–3)

During the community bonding period, I plan to use the time to finalize the bridge adapter design with mentors and resolve any ambiguities in the package categorization.

  • Week 1 (4th May-10th May):
    Align with mentors, finalize bridge design. Walk through the full implementation blueprint and package classification with mentors. Confirm the fork-first development policy. Discuss bundle size thresholds for each package category.

  • Week 2 (11th May-17th May):
    Do a final audit of all 41 packages for inter-package dependency edges that could affect scheduling. Begin the ndarray/from-scijs and ndarray/to-scijs utilities and get mentor feedback on the bridge design.

  • Week 3 (18th May-24th May):
    Complete ndarray/from-scijs and ndarray/to-scijs with full tests. Validate by running 2–3 high priority packages through the bridge end-to-end. Refine the bridge design based on feedback before it becomes the foundation for every subsequent phase.

Development Period (Weeks 1–12)

  • Week 1 (25th May-31st May):
    Start High Priority Clean Delegates (batch 1): Integrate zeros, isndarray, ndarray-concat-rows, ndarray-concat-cols.

  • Week 2 (1st June-7th June):
    Complete Clean Delegates (Batch 2): ndarray-gemm, gauss-random + start Wrap/Adapter: ndarray-pack, ndarray-unpack, ndarray-fill

Measure bundle size before/after (cwise ~16.9 kB gzip vs @stdlib/ndarray/fill-by ~35.3 kB — the ~18 kB increase sets the baseline for comparisons)

  • Week 3 (8th June-14th June):
    Begin High Priority Partial Delegates (Batch 1): ndarray-ops, ndarray-squeeze, ndarray-unsqueeze

ndarray-ops is the most complex package in Batch 1. It exposes many operations (add, sub, mul, div, and more) all routed through cwise.

  • Week 4 (15th June-21st June):
    Continue Partial Delegates (Batch 2): ndarray-linspace, ndarray-normalize, ndarray-sort

ndarray-linspace requires implementing a multi-dimensional ndarray wrapper around stdlib's 1D linspace. The existing scijs API supports an optional out parameter and multi-dim output arrays and the stdlib equivalent only covers 1D.

  • Week 5 (22nd June-28th June):
    Complete Partial Delegates (Batch 3): ndarray-householder-qr, ndarray-distance, ndarray-moments

  • Week 6 (29th June-5th July): (midterm)
    Finish High Priority Packages for midterm evaluation with per-package bundle size measurements, and test coverage report.
    Start Medium Priority: Implement then Delegate/Wrap (Batch 1): ndarray-linear-solve, ndarray-trace, ndarray-determinant.

  • Week 7 (6th July-12th July):
    Continue Implement then Delegate/Wrap (Batch 2): ndarray-fft, sphere-random, ndarray-lup-factorisation, ndarray-lup-solve

  • Week 8 (13th July-19th July):
    Implement BLAS Extraction (Batch 1): ndarray-blas-level1, ndarray-blas-level2

The BLAS extraction pattern is distinct from delegation: stdlib BLAS functions take (N, data, stride, offset) as separate arguments, so the ndarray object cannot be passed directly thus fields must be extracted explicitly using .ndarray(). This pattern must be established cleanly here since ndarray-blas-gemv, ndarray-blas-dger, and ndarray-blas-trsv follow it too.

  • Week 9 (20th July-26th July):
    Complete BLAS Extraction (Batch 2): ndarray-blas-gemv, ndarray-blas-dger, ndarray-blas-trsv + implement ndarray-diagonal

  • Week 10 (27th July-2nd August):
    Start Low Priority New APIs (Batch 1): ndarray-band, ndarray-tile, ndarray-stencil

  • Week 11 (3rd August-9th August):
    Start New APIs (Batch 2): ndarray-gradient, ndarray-select, ndarray-linear-interpolate
    Code freeze, documentation, buffer. No new feature work. Complete any previous backlog. Do a full pass on documentation and test coverage across 37 packages. Verify bundle size measurements are recorded per PR.

  • Week 12 (10th August-16th August):
    Discuss with mentors (ndarray-band, ndarray-tile, ndarray-stencil, ndarray-gradient, ndarray-select, ndarray-linear-interpolate) for post-GSoC planning as these require new stdlib APIs and are the right candidates for continued work after the program.

Submission

  • Final Week (17th August-24th August):
    Submit final project report with: full package integration status, per-package bundle size before/after table, design decisions made during implementation (especially for the bridge utilities) and the roadmap for the cannot-delegate packages.

After GSoC, I intend to continue contributing to stdlib. The new stdlib API implementations will not fit within 12 weeks alongside the core integration work, and I plan to complete it post-GSoC.

Thank you for taking the time to read my proposal!

Notes:

  • The community bonding period is a 3 week period built into GSoC to help you get to know the project community and participate in project discussion. This is an opportunity for you to setup your local development environment, learn how the project's source control works, refine your project plan, read any necessary documentation, and otherwise prepare to execute on your project project proposal.
  • Usually, even week 1 deliverables include some code.
  • By week 6, you need enough done at this point for your mentor to evaluate your progress and pass you. Usually, you want to be a bit more than halfway done.
  • By week 11, you may want to "code freeze" and focus on completing any tests and/or documentation.
  • During the final week, you'll be submitting your project.

Related issues

GSoC Idea #G177

Checklist

  • I have read and understood the Code of Conduct.
  • I have read and understood the application materials found in this repository.
  • I understand that plagiarism will not be tolerated, and I have authored this application in my own words.
  • I have read and understood the patch requirement which is necessary for my application to be considered for acceptance.
  • I have read and understood the stdlib showcase requirement which is necessary for my application to be considered for acceptance.
  • The issue name begins with [RFC]: and succinctly describes your proposal.
  • I understand that, in order to apply to be a GSoC contributor, I must submit my final application to https://summerofcode.withgoogle.com/ before the submission deadline.

Metadata

Metadata

Assignees

No one assigned

    Labels

    20262026 GSoC proposal.rfcProject proposal.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions