poppygl 0.0.21 → 0.0.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -204,8 +204,10 @@ declare function renderGLTFToPNGBufferFromURL(url: string, options?: RenderGLTFT
204
204
  type RenderGLTFToPNGBufferFromGLBBufferOptions = RenderOptionsInput;
205
205
  declare function renderGLTFToPNGBufferFromGLBBuffer(glb: ArrayBuffer | Uint8Array, options?: RenderGLTFToPNGBufferFromGLBBufferOptions): Promise<Buffer>;
206
206
 
207
- declare function renderGLTFToPNGBuffer(gltfPathOrString: string, options?: RenderOptionsInput): Promise<Buffer>;
207
+ interface RenderGLTFToPNGBufferOptions extends RenderOptionsInput, LoadGLTFWithResourcesFromURLOptions {
208
+ }
209
+ declare function renderGLTFToPNGBuffer(gltfOrJson: string | any, options?: RenderGLTFToPNGBufferOptions, resources?: GLTFResources): Promise<Buffer>;
208
210
 
209
211
  declare function renderSceneFromGLTF(scene: GLTFScene, options?: RenderOptionsInput, imageFactory?: ImageFactory): RenderResult;
210
212
 
211
- export { type BitmapLike, type Camera, type CameraRotation, type CameraUp, DEFAULT_LIGHT_DIR, DEFAULT_RENDER_OPTIONS, type DebugPoint, type DrawCall, type FetchLike, type GLTFResources, type GLTFScene, type GridOptions, type ImageFactory, type LightSettings, type LoadGLTFWithResourcesFromURLOptions, type Material, type MutableRGBA, type RGBA, type RenderGLTFToPNGBufferFromGLBBufferOptions, type RenderGLTFToPNGBufferFromURLOptions, type RenderOptions, type RenderOptionsInput, type RenderResult, SoftwareRenderer, bufferFromDataURI, buildCamera, computeSmoothNormals, computeWorldAABB, createGrid, createInfiniteGrid, createSceneFromGLTF, createUint8Bitmap, decodeImageFromBuffer, drawInfiniteGrid, encodePNGToBuffer, getDefaultRenderOptions, hexToRgb, isJPG, isPNG, loadGLTFWithResourcesFromURL, pureImageFactory, renderDrawCalls, renderGLTFToPNGBuffer, renderGLTFToPNGBufferFromGLBBuffer, renderGLTFToPNGBufferFromURL, renderSceneFromGLTF, resolveRenderOptions };
213
+ export { type BitmapLike, type Camera, type CameraRotation, type CameraUp, DEFAULT_LIGHT_DIR, DEFAULT_RENDER_OPTIONS, type DebugPoint, type DrawCall, type FetchLike, type GLTFResources, type GLTFScene, type GridOptions, type ImageFactory, type LightSettings, type LoadGLTFWithResourcesFromURLOptions, type Material, type MutableRGBA, type RGBA, type RenderGLTFToPNGBufferFromGLBBufferOptions, type RenderGLTFToPNGBufferFromURLOptions, type RenderGLTFToPNGBufferOptions, type RenderOptions, type RenderOptionsInput, type RenderResult, SoftwareRenderer, bufferFromDataURI, buildCamera, computeSmoothNormals, computeWorldAABB, createGrid, createInfiniteGrid, createSceneFromGLTF, createUint8Bitmap, decodeImageFromBuffer, drawInfiniteGrid, encodePNGToBuffer, getDefaultRenderOptions, hexToRgb, isJPG, isPNG, loadGLTFWithResourcesFromURL, pureImageFactory, renderDrawCalls, renderGLTFToPNGBuffer, renderGLTFToPNGBufferFromGLBBuffer, renderGLTFToPNGBufferFromURL, renderSceneFromGLTF, resolveRenderOptions };
package/dist/index.js CHANGED
@@ -1612,10 +1612,50 @@ function createSceneFromGLTF(gltf, resources) {
1612
1612
  // lib/gltf/resourceUtils.ts
1613
1613
  import { PassThrough } from "readable-stream";
1614
1614
  import * as PImage from "pureimage";
1615
+
1616
+ // lib/utils/bytes.ts
1617
+ function getNodeBuffer() {
1618
+ const maybeBuffer = globalThis.Buffer;
1619
+ if (!maybeBuffer) {
1620
+ throw new Error("Node Buffer API is not available in this runtime.");
1621
+ }
1622
+ return maybeBuffer;
1623
+ }
1624
+ function toUint8Array(chunk) {
1625
+ if (chunk instanceof Uint8Array) return chunk;
1626
+ if (chunk instanceof ArrayBuffer) return new Uint8Array(chunk);
1627
+ return new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength);
1628
+ }
1629
+ function concatUint8Arrays(chunks) {
1630
+ const totalLength = chunks.reduce((length, chunk) => length + chunk.length, 0);
1631
+ const result = new Uint8Array(totalLength);
1632
+ let offset = 0;
1633
+ for (const chunk of chunks) {
1634
+ result.set(chunk, offset);
1635
+ offset += chunk.length;
1636
+ }
1637
+ return result;
1638
+ }
1639
+ function base64ToUint8Array(base64) {
1640
+ if (typeof globalThis.atob === "function") {
1641
+ const binary = globalThis.atob(base64);
1642
+ const bytes = new Uint8Array(binary.length);
1643
+ for (let i = 0; i < binary.length; i++) {
1644
+ bytes[i] = binary.charCodeAt(i);
1645
+ }
1646
+ return bytes;
1647
+ }
1648
+ return new Uint8Array(getNodeBuffer().from(base64, "base64"));
1649
+ }
1650
+ function uint8ArrayToNodeBuffer(bytes) {
1651
+ return getNodeBuffer().from(bytes);
1652
+ }
1653
+
1654
+ // lib/gltf/resourceUtils.ts
1615
1655
  function bufferFromDataURI(uri) {
1616
1656
  const match = uri.match(/^data:.*?;base64,(.*)$/);
1617
1657
  if (!match) throw new Error(`Unsupported data URI: ${uri.slice(0, 64)}...`);
1618
- return Buffer.from(match[1], "base64");
1658
+ return base64ToUint8Array(match[1]);
1619
1659
  }
1620
1660
  function isPNG(filenameOrUri) {
1621
1661
  return /\.png(\?|$)/i.test(filenameOrUri) || /image\/png/i.test(filenameOrUri);
@@ -1632,7 +1672,7 @@ function detectMimeTypeFromBuffer(buf, hint) {
1632
1672
  }
1633
1673
  function bufferToStream(buf) {
1634
1674
  const stream = new PassThrough();
1635
- stream.end(Buffer.from(buf));
1675
+ stream.end(buf);
1636
1676
  return stream;
1637
1677
  }
1638
1678
  async function decodeImageFromBuffer(buf, mimeType) {
@@ -1808,11 +1848,16 @@ import * as PImage3 from "pureimage";
1808
1848
  async function encodePNGToBuffer(image) {
1809
1849
  const passThrough = new PassThrough2();
1810
1850
  const chunks = [];
1811
- passThrough.on("data", (chunk) => {
1812
- chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
1813
- });
1814
- const resultPromise = new Promise((resolve2, reject) => {
1815
- passThrough.on("end", () => resolve2(Buffer.concat(chunks)));
1851
+ passThrough.on(
1852
+ "data",
1853
+ (chunk) => {
1854
+ chunks.push(toUint8Array(chunk));
1855
+ }
1856
+ );
1857
+ const resultPromise = new Promise((resolve, reject) => {
1858
+ passThrough.on("end", () => {
1859
+ resolve(uint8ArrayToNodeBuffer(concatUint8Arrays(chunks)));
1860
+ });
1816
1861
  passThrough.on("error", reject);
1817
1862
  });
1818
1863
  await PImage3.encodePNGToStream(image, passThrough);
@@ -1908,62 +1953,59 @@ async function renderGLTFToPNGBufferFromGLBBuffer(glb, options = {}) {
1908
1953
  return encodePNGToBuffer(bitmap);
1909
1954
  }
1910
1955
 
1911
- // cli/loadGLTFWithResources.ts
1912
- import * as fs from "fs";
1913
- import * as path from "path";
1914
- async function loadGLTFWithResources(gltfPath) {
1956
+ // lib/gltf/loadGLTFWithResourcesFromPath.ts
1957
+ async function loadGLTFWithResourcesFromPath(gltfPath) {
1958
+ const fs = await import("fs/promises");
1959
+ const path = await import("path");
1915
1960
  const baseDir = path.dirname(gltfPath);
1916
- const gltf = JSON.parse(await fs.promises.readFile(gltfPath, "utf8"));
1961
+ const gltf = JSON.parse(await fs.readFile(gltfPath, "utf8"));
1917
1962
  const buffers = await Promise.all(
1918
- (gltf.buffers || []).map(async (b) => {
1919
- if (b.uri && b.uri.startsWith("data:")) {
1920
- return bufferFromDataURI(b.uri);
1963
+ (gltf.buffers || []).map(async (buffer) => {
1964
+ if (buffer.uri?.startsWith("data:")) {
1965
+ return bufferFromDataURI(buffer.uri);
1921
1966
  }
1922
- if (b.uri) {
1923
- const resolved = path.resolve(baseDir, decodeURIComponent(b.uri));
1924
- return fs.promises.readFile(resolved);
1967
+ if (buffer.uri) {
1968
+ const resolved = path.resolve(baseDir, decodeURIComponent(buffer.uri));
1969
+ return fs.readFile(resolved);
1925
1970
  }
1926
1971
  throw new Error("Buffer without uri not supported in this loader.");
1927
1972
  })
1928
1973
  );
1929
1974
  const images = await Promise.all(
1930
- (gltf.images || []).map(async (img) => {
1931
- if (img.uri) {
1932
- if (img.uri.startsWith("data:")) {
1933
- const buf = bufferFromDataURI(img.uri);
1934
- return decodeImageFromBuffer(buf, img.mimeType);
1975
+ (gltf.images || []).map(async (image) => {
1976
+ if (image.uri) {
1977
+ if (image.uri.startsWith("data:")) {
1978
+ const bytes = bufferFromDataURI(image.uri);
1979
+ return decodeImageFromBuffer(bytes, image.mimeType);
1935
1980
  }
1936
- const filePath = path.resolve(baseDir, decodeURIComponent(img.uri));
1937
- const fileBuf = await fs.promises.readFile(filePath);
1938
- const hintedMime = isPNG(img.uri) ? "image/png" : isJPG(img.uri) ? "image/jpeg" : img.mimeType;
1939
- return decodeImageFromBuffer(fileBuf, hintedMime);
1981
+ const filePath = path.resolve(baseDir, decodeURIComponent(image.uri));
1982
+ const fileBytes = await fs.readFile(filePath);
1983
+ const hintedMime = isPNG(image.uri) ? "image/png" : isJPG(image.uri) ? "image/jpeg" : image.mimeType;
1984
+ return decodeImageFromBuffer(fileBytes, hintedMime);
1940
1985
  }
1941
- if (typeof img.bufferView === "number") {
1942
- const bufferView = gltf.bufferViews?.[img.bufferView];
1986
+ if (typeof image.bufferView === "number") {
1987
+ const bufferView = gltf.bufferViews?.[image.bufferView];
1943
1988
  if (!bufferView) {
1944
- throw new Error(`Invalid image bufferView index ${img.bufferView}`);
1989
+ throw new Error(`Invalid image bufferView index ${image.bufferView}`);
1945
1990
  }
1946
1991
  const buffer = buffers[bufferView.buffer];
1947
- if (!buffer)
1992
+ if (!buffer) {
1948
1993
  throw new Error(
1949
- `Missing buffer for image bufferView ${img.bufferView}`
1994
+ `Missing buffer for image bufferView ${image.bufferView}`
1950
1995
  );
1996
+ }
1951
1997
  const byteOffset = bufferView.byteOffset ?? 0;
1952
1998
  const byteLength = bufferView.byteLength;
1953
1999
  if (typeof byteLength !== "number") {
1954
2000
  throw new Error(
1955
- `bufferView ${img.bufferView} missing byteLength for image.`
2001
+ `bufferView ${image.bufferView} missing byteLength for image.`
1956
2002
  );
1957
2003
  }
1958
- const slice = Buffer.from(
1959
- buffer.buffer,
1960
- buffer.byteOffset + byteOffset,
1961
- byteLength
1962
- );
1963
- return decodeImageFromBuffer(slice, img.mimeType);
2004
+ const slice = buffer.subarray(byteOffset, byteOffset + byteLength);
2005
+ return decodeImageFromBuffer(slice, image.mimeType);
1964
2006
  }
1965
2007
  throw new Error(
1966
- "images[*] entry missing uri or bufferView; unsupported in this lightweight loader."
2008
+ "images[*] entry missing uri or bufferView; unsupported in this loader."
1967
2009
  );
1968
2010
  })
1969
2011
  );
@@ -1976,22 +2018,58 @@ async function loadGLTFWithResources(gltfPath) {
1976
2018
  };
1977
2019
  }
1978
2020
 
1979
- // cli/renderGLTFToPNGBuffer.ts
1980
- async function renderGLTFToPNGBuffer(gltfPathOrString, options = {}) {
1981
- let gltf;
1982
- let resources;
2021
+ // lib/gltf/resolveGLTFInput.ts
2022
+ function isNodeRuntime() {
2023
+ const runtimeProcess = globalThis.process;
2024
+ return !!runtimeProcess?.versions?.node;
2025
+ }
2026
+ function isFetchableURLInNode(source) {
1983
2027
  try {
1984
- gltf = JSON.parse(gltfPathOrString);
1985
- resources = { buffers: [], images: [] };
2028
+ const url = new URL(source);
2029
+ return ["http:", "https:", "data:", "blob:"].includes(url.protocol);
1986
2030
  } catch {
1987
- const result = await loadGLTFWithResources(gltfPathOrString);
1988
- gltf = result.gltf;
1989
- resources = result.resources;
2031
+ return false;
2032
+ }
2033
+ }
2034
+ function parseGLTFJSON(source) {
2035
+ try {
2036
+ return JSON.parse(source);
2037
+ } catch (error) {
2038
+ if (error instanceof SyntaxError) return null;
2039
+ throw error;
1990
2040
  }
2041
+ }
2042
+ async function resolveGLTFInput(source, options = {}) {
2043
+ const gltf = parseGLTFJSON(source);
2044
+ if (gltf !== null) {
2045
+ return {
2046
+ gltf,
2047
+ resources: { buffers: [], images: [] }
2048
+ };
2049
+ }
2050
+ if (!isNodeRuntime()) {
2051
+ return loadGLTFWithResourcesFromURL(source, options);
2052
+ }
2053
+ if (isFetchableURLInNode(source)) {
2054
+ return loadGLTFWithResourcesFromURL(source, options);
2055
+ }
2056
+ return loadGLTFWithResourcesFromPath(source);
2057
+ }
2058
+
2059
+ // lib/render/renderGLTFToPNGBuffer.ts
2060
+ function renderFromGLTF(gltf, options, resources) {
1991
2061
  const scene = createSceneFromGLTF(gltf, resources);
1992
- const { bitmap } = renderSceneFromGLTF(scene, options, pureImageFactory);
2062
+ const { bitmap } = renderDrawCalls(scene.drawCalls, options, pureImageFactory);
1993
2063
  return encodePNGToBuffer(bitmap);
1994
2064
  }
2065
+ async function renderGLTFToPNGBuffer(gltfOrJson, options = {}, resources = { buffers: [], images: [] }) {
2066
+ const { fetchImpl, ...renderOptions } = options;
2067
+ if (typeof gltfOrJson !== "string") {
2068
+ return renderFromGLTF(gltfOrJson, renderOptions, resources);
2069
+ }
2070
+ const loaded = await resolveGLTFInput(gltfOrJson, { fetchImpl });
2071
+ return renderFromGLTF(loaded.gltf, renderOptions, loaded.resources);
2072
+ }
1995
2073
 
1996
2074
  // lib/index.ts
1997
2075
  function renderSceneFromGLTF(scene, options, imageFactory) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "poppygl",
3
3
  "main": "dist/index.js",
4
- "version": "0.0.21",
4
+ "version": "0.0.23",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "https://github.com/tscircuit/poppygl.git"