Multi-file projects in Code Mode

Organize your Code Mode scripts across multiple files using imports, exports, and package.json configuration.

Multi-file projects in Code Mode

As your scripts grow, you can organize code across multiple files. This makes complex projects more manageable and allows you to reuse utility functions across different scripts.

Adding files

To add a new file to your project:

  1. Click the + button in the file tab bar above the editor
  2. Enter a filename with a .ts or .js extension (for example, utils.ts or lib/helpers.ts)
  3. Click Add File

The new file opens in the editor and appears as a tab in the file bar.

File naming

  • Use relative paths like utils.ts or lib/helpers.ts
  • Files must have .ts or .js extensions
  • Filenames can contain letters, numbers, underscores, hyphens, and forward slashes

Closing files

To close a file, click the X on its tab. You cannot close the main file (main.ts) or package.json.

Closing a file removes it from the project. If you need the file again, you must re-add it.

Importing between files

Use standard ES module syntax to import and export between files.

Exporting from a file

Export functions, constants, or types from a file:

// utils.ts
export function createRoundedCube(size: number, radius: number) {
  // implementation
}

export const DEFAULT_SEGMENTS = 32;

Importing into another file

Import using relative paths with ./:

// main.ts
import { createRoundedCube, DEFAULT_SEGMENTS } from './utils';
import { Manifold } from 'manifold-3d/manifoldCAD';

const cube = createRoundedCube(20, 2);

export const result = cube;

Nested directories

For files in subdirectories, use the full relative path:

// main.ts
import { helperFunction } from './lib/helpers';
import { constants } from './config/settings';

The package.json file

Every project includes a package.json file that CADit manages automatically. This file tracks your project's dependencies and configuration.

Automatic updates

When you import npm packages in your code, CADit detects them and updates package.json automatically. For example, if you add:

import _ from 'lodash';

CADit adds lodash to the dependencies in package.json.

Manual editing

You can edit package.json directly to:

  • Pin specific package versions
  • Add packages before using them in code
  • Set the project name

Example package.json:

{
  "name": "@cadit-app/my-project",
  "version": "1.0.0",
  "type": "module",
  "dependencies": {
    "lodash": "^4.17.21"
  }
}

The main entry point

The main.ts file (or whatever file appears first in the tab bar) is the entry point. This file must export a result variable or use defineParams with a main function.

If you rename the main file or want to use a different entry point, update the main file name in your project settings.

Example: Organizing a parametric design

Here is how you might structure a multi-file parametric design:

geometry.ts - Reusable geometry functions:

import { Manifold } from 'manifold-3d/manifoldCAD';

export function createFilletedBox(
  width: number,
  height: number,
  depth: number,
  radius: number
) {
  // Create box with filleted edges
  const box = Manifold.cube([width, height, depth], true);
  // ... filleting logic
  return box;
}

export function createMountingHole(diameter: number, depth: number) {
  return Manifold.cylinder(depth, diameter / 2);
}

constants.ts - Shared constants:

export const WALL_THICKNESS = 2;
export const MOUNTING_HOLE_DIAMETER = 4;
export const DEFAULT_FILLET_RADIUS = 1;

main.ts - Main entry point with parameters:

import { defineParams } from '@cadit-app/script-params';
import { Manifold } from '@cadit-app/manifold-3d/manifoldCAD';
import { createFilletedBox, createMountingHole } from './geometry';
import { WALL_THICKNESS, MOUNTING_HOLE_DIAMETER } from './constants';

export default defineParams({
  params: {
    width: { type: 'slider', default: 50, min: 20, max: 100 },
    height: { type: 'slider', default: 30, min: 10, max: 60 },
    depth: { type: 'slider', default: 50, min: 20, max: 100 },
    addHoles: { type: 'switch', default: true, label: 'Add mounting holes' },
  },
  main: (params) => {
    const box = createFilletedBox(
      params.width,
      params.height,
      params.depth,
      2
    );

    if (!params.addHoles) {
      return box;
    }

    const hole = createMountingHole(MOUNTING_HOLE_DIAMETER, WALL_THICKNESS + 1);
    const holePositions = [
      [params.width / 4, 0, params.depth / 4],
      [-params.width / 4, 0, params.depth / 4],
      [params.width / 4, 0, -params.depth / 4],
      [-params.width / 4, 0, -params.depth / 4],
    ];

    let result = box;
    for (const [x, y, z] of holePositions) {
      result = result.subtract(
        hole.translate([x, -params.height / 2, z])
      );
    }

    return result;
  },
});

Tips

  • Keep utility functions in separate files for reusability
  • Use a constants.ts file for values used in multiple places
  • Keep main.ts focused on the high-level structure
  • Name files descriptively to communicate their purpose
  • Use subdirectories like lib/ for helper modules if your project grows large

Next steps