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