Skip to content

Data Model (Schema V3) ​

The project data model is defined in src/types/parallax.ts and validated/normalized by src/core/schema.ts. All import/export operations use this schema.

Object Graph ​

The following diagram shows the relationships between the main types in the project schema:

Compatibility ​

Schema v3 is a strict format. v2 payloads are intentionally rejected — there is no migration path.

Root Structure ​

ts
type ParallaxDesignerProject = {
  version: 3;
  scene: SceneConfig;
  harmonics: FloatHarmonics;
  layers: ParallaxLayer[];  // max: 30
  ui: UiState;
};

Scene ​

ts
type SceneConfig = {
  maxRot: number;                  // 0 .. 10
  containerLerp: number;           // 0.005 .. 0.3
  perspective: number;             // 200 .. 2000
  documentBackgroundColor: string; // CSS color
};

Harmonics ​

ts
type FloatHarmonics = {
  freqA: number;  // 0 .. 3
  freqB: number;  // 0 .. 3
  ampB: number;   // 0 .. 1
  freqC: number;  // 0 .. 3
  freqD: number;  // 0 .. 3
  ampD: number;   // 0 .. 1
};

Layer ​

ts
type ParallaxLayer = {
  id: string;
  presetKey?: string;
  name: string;
  imageSrc: string;     // URL, relative path, or idb://asset/<id>
  visible: boolean;

  geometry: {
    topPct: number;     // -50 .. 50
    leftPct: number;    // -50 .. 50
    widthPct: number;   // 50 .. 180
    heightPct: number;  // 50 .. 180
    zIndex: number;     // 1 .. 30
    baseZ: number;      // -300 .. 100
    baseScale: number;  // 0.8 .. 1.5
  };

  background: {
    position: {
      anchorX: "left" | "center" | "right";
      anchorY: "top" | "center" | "bottom";
      offsetXPct: number;  // -100 .. 100
      offsetYPct: number;  // -100 .. 100
    };
    size: {
      mode: "cover" | "contain" | "auto" | "custom";
      widthPct: number;    // 1 .. 400
      heightPct: number;   // 1 .. 400
    };
    repeat: {
      x: "repeat" | "no-repeat" | "round" | "space";
      y: "repeat" | "no-repeat" | "round" | "space";
    };
    color: string;         // CSS color
    blendMode: BlendMode;  // 16 CSS blend modes
    origin: BoxModel;      // border-box | padding-box | content-box
    clip: BoxModel;
  };

  motion: {
    lerp: number;          // 0.005 .. 0.3
    scaleBoost: number;    // 0 .. 0.1
    moveX: number;         // 0 .. 80
    moveY: number;         // 0 .. 80
    floatX: number;        // 0 .. 20
    floatY: number;        // 0 .. 20
    floatSpeed: number;    // 0 .. 0.002
  };
};

UI State ​

ts
type UiState = {
  panelVisible: boolean;
  fpsVisible: boolean;
  mode: "tune" | "runtime";
  selectedLayerId: string | null;
};

Validation Rules ​

The schema validator (src/core/schema.ts) applies these rules on import/load:

RuleBehavior
version must equal 3Rejected if not exactly 3
Enum fields must match allowed valuesRejected on invalid enum
Numerics must be finiteNaN / Infinity rejected
Color strings must be valid CSSRejected on parse failure
Out-of-range numericsAutomatically clamped to schema-defined ranges
Layer count above 30Trimmed from the end
Numeric step valuesClamped only — no step snapping

Result Pattern ​

Validation returns a Result<T, E> instead of throwing exceptions:

ts
type Result<T, E> = { ok: true; data: T } | { ok: false; error: E };

On success, the data field contains the validated and normalized project. On failure, the error field contains a descriptive message.

Normalization Summary ​

When values are clamped or layers trimmed during import, a ProjectNormalizationSummary is generated listing all adjustments. This is displayed to the user so they know exactly what changed.

Constraints ​

Numeric constraints (min, max, step) for every field are defined in src/core/projectConstraints.ts and shared between:

  • The schema validator (for clamping)
  • UI slider controls (for input ranges and step increments)

Step Values ​

CategoryFieldStep
ScenemaxRot0.1
ScenecontainerLerp0.005
Sceneperspective10
Harmonicsfreq*0.05
Harmonicsamp*0.05
Geometrytop/left/width/height0.25
GeometryzIndex1
GeometrybaseZ1
GeometrybaseScale0.0025
Motionlerp0.005
MotionscaleBoost0.001
MotionmoveX/Y1
MotionfloatX/Y0.5
MotionfloatSpeed0.00001
Backgroundsize width/height1
Backgroundposition offsets1

Storage & Share Keys ​

Storage LocationKey / PathContent
localStorageparallax-designer-localeLocale preference (app-level only)
IndexedDBDB: parallax-designer-assets-v2Assets + custom presets
IndexedDB tableassetsUploaded image blobs
IndexedDB tablecustomPresetsNamed project snapshots

Local Upload References ​

Uploaded images are stored as blobs in IndexedDB and referenced in project payloads as idb://asset/<id>. These references are valid only in the browser profile that contains the corresponding IndexedDB record.

Copy JSON preserves these references and surfaces a portability warning. Download HTML offers an IDB handling mode (inline data URLs or blank placeholders).

Custom Presets ​

Custom presets are stored in IndexedDB (customPresets table) and are not embedded in exported project JSON. Each record contains:

  • name — User-assigned preset name
  • Full ParallaxDesignerProject payload
  • createdAt, updatedAt — Timestamps
  • layerCount — Number of layers in the snapshot

Parallax Designer Documentation

Scroll to zoom · Drag to pan