This document covers the full public API of the fspy-calibrator Angular library.
For installation and quick start, see the README. For internal architecture, see ARCHITECTURE.md. For the original fSpy concepts (vanishing points, calibration workflow, camera math), see fspy.io.
(NPM package not available yet, copy the source code manually in your project)
Import the component in your standalone Angular component or module:
import { CalibratorComponent } from 'fspy-calibrator';
@Component({
imports: [CalibratorComponent],
// ...
})
export class YourComponent {}The single entry point for the library. Drop it into any Angular template and give it a host element with explicit dimensions.
<fspy-calibrator
[imageUrl]="imageSrc"
[cameraDistanceScale]="10"
(calibrationChange)="onCalibration($event)"
(threeCameraChange)="onThreeCamera($event)">
</fspy-calibrator>/* The component fills its host 100% — always set an explicit size */
fspy-calibrator {
display: block;
width: 100%;
height: 600px;
}@Input() imageUrl: string | nullURL or base64 data URL of the image to calibrate. The component loads the image internally via HTMLImageElement — no pre-loading required in the parent.
- On change: image is rendered in the canvas, control points reset to defaults, solver runs immediately.
- On
nullor empty string: canvas clears, both outputs emitnull.
@Input() cameraDistanceScale: number // default: 10Controls how far the camera is placed from the scene origin in the output. This value is passed to the solver as the base camera distance scale.
- When a reference distance is configured in the settings panel,
cameraDistanceScaleacts as the base before the reference-distance ratio is applied. - Can be changed at any time; the component reacts immediately and re-emits both outputs.
- Useful for scaling the
ThreeCameraConfigcamera position to match your Three.js scene units.
@Output() calibrationChange: EventEmitter<CameraParameters | null>Emits the raw fSpy CameraParameters object on every solver update. Emits null when:
- No image is loaded
- The calibration is geometrically invalid (e.g. near-parallel vanishing lines)
@Output() threeCameraChange: EventEmitter<ThreeCameraConfig | null>Emits a Three.js-ready camera configuration derived from the solver result. Emits null under the same conditions as calibrationChange.
Use the exported applyThreeCameraConfig helper to apply this to a THREE.PerspectiveCamera.
Only 2 Vanishing Points (2VP) is supported. The VP count selector is visible in the UI but locked to 2. The 1VP code path is not implemented.
All three fSpy principal point modes are supported:
| Mode | Description |
|---|---|
ImageMidpoint |
Principal point fixed at the image centre (default) |
Manual |
A draggable marker appears on the canvas; user positions it freely |
FromThirdVanishingPoint |
A third VP control appears; its intersection computes the principal point |
When enabled, calibration simplifies to 4 draggable corner points of a rectangular feature in the image. VP2 is derived automatically.
Raw solver output, numerically identical to fSpy (tolerance ≤ 1e-4). This is the same type fSpy writes to its .fspy project files.
interface CameraParameters {
// Camera-to-world transform matrix (4x4, row-major)
cameraTransform: {
rows: [
[number, number, number, number],
[number, number, number, number],
[number, number, number, number],
[number, number, number, number]
]
}
// Horizontal and vertical field of view in radians
horizontalFieldOfView: number
verticalFieldOfView: number
// Principal point as relative coordinates [0, 1]
principalPoint: { x: number; y: number }
// Vanishing point axes assignments
vanishingPointAxes: [Axis, Axis] // VP1 axis, VP2 axis
// Present when reference distance is configured
relativeFocalLength?: number
}For the full fSpy type definitions, see
src/types/— the verbatim copy from the original fSpy source.
Derived from CameraParameters with Three.js coordinate conventions applied (Y-up, right-handed, column-major matrix).
interface ThreeCameraConfig {
// Vertical field of view in degrees (converted from radians)
fov: number
// Aspect ratio derived from image dimensions (width / height)
aspect: number
// Clipping planes
near: number // default: 0.1
far: number // default: 1000
// Camera-to-world matrix: Three.js column-major, Y-up convention
cameraMatrix: [
number, number, number, number,
number, number, number, number,
number, number, number, number,
number, number, number, number
]
}import { applyThreeCameraConfig } from 'fspy-calibrator';
applyThreeCameraConfig(camera: THREE.PerspectiveCamera, config: ThreeCameraConfig): voidConvenience helper that applies all fields from a ThreeCameraConfig to a Three.js camera:
- Sets
camera.fov,camera.aspect,camera.near,camera.far - Sets
camera.matrixfromconfig.cameraMatrix - Disables
camera.matrixAutoUpdate - Calls
camera.updateProjectionMatrix()
import * as THREE from 'three';
import { applyThreeCameraConfig, ThreeCameraConfig } from 'fspy-calibrator';
const camera = new THREE.PerspectiveCamera();
onThreeCamera(config: ThreeCameraConfig | null) {
if (config) {
applyThreeCameraConfig(camera, config);
renderer.render(scene, camera);
}
}// app.component.ts
import { Component } from '@angular/core';
import * as THREE from 'three';
import {
CalibratorComponent,
CameraParameters,
ThreeCameraConfig,
applyThreeCameraConfig
} from 'fspy-calibrator';
@Component({
selector: 'app-root',
imports: [CalibratorComponent],
template: `
<fspy-calibrator
[imageUrl]="imageUrl"
[cameraDistanceScale]="distanceScale"
(calibrationChange)="onCalibration($event)"
(threeCameraChange)="onThreeCamera($event)">
</fspy-calibrator>
<button (click)="loadImage()">Load image</button>
<button (click)="downloadJson()" [disabled]="!cameraParams">
Download CameraParameters
</button>
`,
})
export class AppComponent {
imageUrl: string | null = null;
distanceScale = 10;
cameraParams: CameraParameters | null = null;
private camera = new THREE.PerspectiveCamera();
loadImage() {
this.imageUrl = 'https://example.com/photo.jpg';
// or read from a file input as a data URL
}
onCalibration(params: CameraParameters | null) {
this.cameraParams = params;
}
onThreeCamera(config: ThreeCameraConfig | null) {
if (config) {
applyThreeCameraConfig(this.camera, config);
// renderer.render(scene, this.camera);
}
}
downloadJson() {
const blob = new Blob(
[JSON.stringify(this.cameraParams, null, 2)],
{ type: 'application/json' }
);
const a = document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = 'camera-params.json';
a.click();
}
}| Export | Kind | Description |
|---|---|---|
CalibratorComponent |
Component | The <fspy-calibrator> entry point |
CameraParameters |
Type | Raw fSpy solver output |
ThreeCameraConfig |
Type | Three.js-ready camera configuration |
applyThreeCameraConfig |
Function | Applies ThreeCameraConfig to a THREE.PerspectiveCamera |
CalibrationStateService |
Service | Internal state service (advanced use only) |
- 1VP calibration is not supported. The component is locked to 2 vanishing points.
- SSR is not supported. The component uses
HTMLImageElement, Konva.js canvas, and browser APIs — it requires a browser environment. - Mobile touch is not optimised. Drag interactions are designed for mouse/pointer events.