Models and shaders
Publish a real glTF model with orbit controls, a static poster, and an original-file download.
Model displays an uncompressed glTF 2.0 .glb or .gltf file with Three.js. Alkemist provides the figure shell, lazy loading, camera controls, theming, fallback, and cleanup. The file itself stays downloadable.
Add a model
Place the model and any associated textures in your site’s public directory. A self-contained GLB is convenient for publishing; a .gltf document can reference separate binary and texture files, whose relative URLs must remain valid.
import Model from '@alkemdotdev/alkemist-components/model';
<Model
src="/test/torus-knot.glb"
poster="/test/torus-knot.svg"
title="A (2, 3) torus knot"
parameters={['view', 'wireframe']}
description="A deterministic tube mesh around a closed torus-knot curve."
/>Model
Preview loads when it becomes visible.
Component parameters
Source code
---
import Model from "@alkemdotdev/alkemist-components/model";
---
<Model
id={""}
src={"/test/torus-knot.glb"}
title={"A torus knot"}
description={"Drag to inspect this generated teaching mesh."}
poster={"/test/torus-knot.svg"}
view={"perspective"}
wireframe={false}
parameters={false}
class={""}
/>The component uses the project’s pinned Three.js GLTFLoader. It does not currently configure Draco, Meshopt, or KTX2 decoders, so models depending on those compression extensions need an uncompressed export.
Props
The public prop type is ModelProps.
| Prop | Required | Meaning |
|---|---|---|
src | Yes | Model URL |
title | Yes | Visible figure title and accessible control label |
description | No | Context, provenance, units, or an explanation of the geometry |
poster | No | Static image shown while loading and when the interactive renderer is unavailable |
view | No | Initial camera: perspective (default), front, or top |
wireframe | No | Display wireframes initially; false restores authored material settings |
parameters | No | false (default), true, or a list of view and wireframe controls |
class | No | Additional class on the figure’s custom element |
Include a meaningful poster and description for published research. A poster is optional in the API, but it gives readers useful content before the GPU viewer starts and if their browser cannot render the scene.
Interaction
- Drag to orbit. Hold Shift while scrolling to zoom, so ordinary scrolling can continue through the containing article.
- Reset view stays visible; View options groups Front, Top, Wireframe, and Spin without taking a permanent toolbar row.
- Focus the canvas and use the arrow keys to orbit,
+/−to zoom, and Home to reset.
Spin starts off, pauses offscreen, and stops when the reduced-motion preference changes to reduce.
Orbit navigation uses Three.js OrbitControls. The canvas and controls expose keyboard labels, but a 3D canvas is not a complete nonvisual representation of complex geometry. The title, description, poster, and original file are part of the figure’s accessible content.
The shared parameter API exposes getParameters(), atomic setParameters(patch), and alk:parameters-change on the mounted alk-model. Parameter controls and View options stay in sync. Reset values restores authored props; Reset view and Home return the camera to perspective. The mesh and canvas survive parameter changes and Focus / Read / Present transitions. Try the live figures lab.
Theme and lifecycle
The board color determines the scene background. Ordinary model materials retain their authored colors. Alkemist’s own teaching fixture opts into the shared cobalt ink with material metadata extras: { Ink: "cobalt" }, so that material uses the same #1982f2 on whiteboard and blackboard.
The engine imports when the viewer approaches the viewport. Idle and offscreen scenes do not run a continuous animation loop. Rendering caps device pixel ratio at 2; removed viewers release geometry, materials, textures, renderer resources, and decoded image bitmaps. These explicit disposals follow Three.js resource cleanup guidance.
A network or WebGL failure leaves the static poster, explanatory state, and original download available. It does not replace the requested model with an unrelated synthetic object.
The specimen and current limits
The torus-knot fixture is generated by scripts/generate-test-model.mjs. Its poster and GLB belong to this repository and can be regenerated. The test page exercises the viewer alongside other media.
This version has no animation timeline, skeletal animation controls, measurement tools, physical unit conversion, mesh editing, or model generation. NeRF exports, Gaussian splats, point clouds, STL/OBJ adapters, and robotics/URDF viewers remain separate future capabilities. A shared figure design does not make their file formats interchangeable.
A live shader study
Shader is a reusable, bounded two-source interference specimen. It evaluates a dimensionless field in GLSL, with frequency and source-angle controls. The eight categorical inks distinguish contour bands; a static SVG remains visible until the GPU renderer is ready.
import Shader from '@alkemdotdev/alkemist-components/shader';
<Shader title="Interference field" frequency={9} angle={24} />Shader
Preview loads when it becomes visible.
Component parameters
Source code
---
import Shader from "@alkemdotdev/alkemist-components/shader";
---
<Shader
id={""}
title={"Two wave sources"}
frequency={9}
angle={24}
parameters={true}
class={""}
/>Change Frequency and Source angle to compare the field; enable Play waves to animate it.
Its public prop type is ShaderProps. title defaults to “Interference field,” frequency defaults to 9 and is clamped to 3–18, and angle defaults to 24 degrees and is clamped to 0–180. class adds a custom class. Native range controls let readers change those values; Play waves explicitly starts motion.
The implementation uses WebGL2 and GLSL ES 3.00. While paused, changing a control renders one frame. Playing advances phase at 0.8 radians per second and suspends offscreen or in a hidden tab; changing the reduced-motion preference pauses playback. Device pixel ratio is capped at 2. Missing WebGL2, shader compilation/link failures, and a lost graphics context produce distinct explanatory states. Removal releases the shader program, shader objects, vertex array, observers, and listeners.
The SVG fallback is an illustration of overlapping wave sources, not a screenshot of the computed field. The exact fragment source is exported by the shader module as INTERFERENCE_FRAGMENT for the test page’s source specimen.
This component currently renders its own two-source field. It does not accept an arbitrary shader path, execute untrusted shader code, or provide a general shader editor. The working study is on the test page.