* start of async Signed-off-by: Jess Frazelle <github@jessfraz.com> check at end if the async commands completed Signed-off-by: Jess Frazelle <github@jessfraz.com> run at the end of inner_run Signed-off-by: Jess Frazelle <github@jessfraz.com> set import as async Signed-off-by: Jess Frazelle <github@jessfraz.com> updates Signed-off-by: Jess Frazelle <github@jessfraz.com> updates Signed-off-by: Jess Frazelle <github@jessfraz.com> add to the wasm side Signed-off-by: Jess Frazelle <github@jessfraz.com> updates Signed-off-by: Jess Frazelle <github@jessfraz.com> fmt Signed-off-by: Jess Frazelle <github@jessfraz.com> * fire Signed-off-by: Jess Frazelle <github@jessfraz.com> * flake Signed-off-by: Jess Frazelle <github@jessfraz.com> * fixup for awaiting on import Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * fix mock Signed-off-by: Jess Frazelle <github@jessfraz.com> * fix mock Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * fixes Signed-off-by: Jess Frazelle <github@jessfraz.com> * add a test where we import then do a bunch of other stuff Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * fixup to see Signed-off-by: Jess Frazelle <github@jessfraz.com> * fixups Signed-off-by: Jess Frazelle <github@jessfraz.com> * fix tests Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * cross platform time Signed-off-by: Jess Frazelle <github@jessfraz.com> * fixes Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * another appearance tests Signed-off-by: Jess Frazelle <github@jessfraz.com> * new docs and tests Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * dont loop so tight Signed-off-by: Jess Frazelle <github@jessfraz.com> * fixes Signed-off-by: Jess Frazelle <github@jessfraz.com> --------- Signed-off-by: Jess Frazelle <github@jessfraz.com>
5.7 KiB
title, excerpt, layout
title | excerpt | layout |
---|---|---|
KCL Modules | Documentation of modules for the KCL language for the Zoo Design Studio. | manual |
KCL
allows splitting code up into multiple files. Each file is somewhat
isolated from other files as a separate module.
When you define a function, you can use export
before it to make it available
to other modules.
// util.kcl
export fn increment(x) {
return x + 1
}
Other files in the project can now import functions that have been exported. This makes them available to use in another file.
// main.kcl
import increment from "util.kcl"
answer = increment(41)
Imported files must be in the same project so that units are uniform across modules. This means that it must be in the same directory.
Import statements must be at the top-level of a file. It is not allowed to have
an import
statement inside a function or in the body of an if-else.
Multiple functions can be exported in a file.
// util.kcl
export fn increment(x) {
return x + 1
}
export fn decrement(x) {
return x - 1
}
When importing, you can import multiple functions at once.
import increment, decrement from "util.kcl"
Imported symbols can be renamed for convenience or to avoid name collisions.
import increment as inc, decrement as dec from "util.kcl"
Importing files from other CAD systems
import
can also be used to import files from other CAD systems. The format of the statement is the
same as for KCL files. You can only import the whole file, not items from it. E.g.,
import "tests/inputs/cube.obj"
// Use `cube` just like a KCL object.
import "tests/inputs/cube-2.sldprt" as cube
// Use `cube` just like a KCL object.
You can make the file format explicit using a format attribute (useful if using a different extension), e.g.,
@(format = obj)
import "tests/inputs/cube"
For formats lacking unit data (such as STL, OBJ, or PLY files), the default unit of measurement is millimeters. Alternatively you may specify the unit by using an attirbute. Likewise, you can also specify a coordinate system. E.g.,
@(unitLength = ft, coords = opengl)
import "tests/inputs/cube.obj"
When importing a GLTF file, the bin file will be imported as well.
Import paths are relative to the current project directory. Imports currently only work when using the native Design Studio, not in the browser.
Supported values
File formats: fbx
, gltf
/glb
, obj
+, ply
+, sldprt
, step
/stp
, stl
+. (Those marked with a
'+' support customising the length unit and coordinate system).
Length units: mm
(the default), cm
, m
, inch
, ft
, yd
.
Coordinate systems:
zoo
(the default), forward: -Y, up: +Z, handedness: rightopengl
, forward: +Z, up: +Y, handedness: rightvulkan
, forward: +Z, up: -Y, handedness: left
Performance
Parallelized foreign-file imports now let you overlap file reads, initialization, and rendering. To maximize throughput, you need to understand the three distinct stages—reading, initializing (background render start), and invocation (blocking) —and structure your code to defer blocking operations until the end.
Foreign Import Execution Stages
-
Import (Read) Stage
import "tests/inputs/cube.step" as cube
- Reads the file from disk and makes its API available.
- Does not start Engine rendering or block your script.
-
Initialization (Background Render) Stage
import "tests/inputs/cube.step" as cube myCube = cube // <- This line starts background rendering
- Invoking the imported symbol (assignment or plain call) triggers Engine rendering in the background.
- This kick‑starts the render pipeline but doesn’t block—you can continue other work while the Engine processes the model.
-
Invocation (Blocking) Stage
import "tests/inputs/cube.step" as cube myCube = cube myCube |> translate(z=10) // <- This line blocks
- Any method call (e.g.,
translate
,scale
,rotate
) waits for the background render to finish before applying transformations. - This is the only point where your script will block.
- Any method call (e.g.,
Nuance: Foreign imports differ from pure KCL modules—calling the same import symbol multiple times (e.g.,
screw
twice) starts background rendering twice.
Best Practices
1. Defer Blocking Calls
Initialize early but delay all transformations until after your heavy computation:
import "tests/inputs/cube.step" as cube // 1) Read
myCube = cube // 2) Background render starts
// --- perform other operations and calculations or setup here ---
myCube
|> translate(z=10) // 3) Blocks only here
2. Encapsulate Imports in Modules
Keep main.kcl
free of reads and initialization; wrap them:
// imports.kcl
import "tests/inputs/cube.step" as cube // Read only
export myCube = cube // Kick off rendering
// main.kcl
import myCube from "imports.kcl" // Import the initialized object
// ... computations ...
myCube
|> translate(z=10) // Blocking call at the end
3. Avoid Immediate Method Calls
import "tests/inputs/cube.step" as cube
cube
|> translate(z=10) // Blocks immediately, negating parallelism
Both calling methods right on cube
immediately or leaving an implicit import without assignment introduce blocking.
Future Improvements
Upcoming releases will auto‑analyze dependencies and only block when truly necessary. Until then, explicit deferral and modular wrapping give you the best performance.