This commit is contained in:
2026-10-05 13:52:45 -04:00
parent 9eb71e9855
commit e90ebde399
34 changed files with 465 additions and 581 deletions
+1
View File
@@ -0,0 +1 @@
{"branding":{"colorScheme":"light","fonts":[{"family":"Inter","role":"body"},{"family":"Roboto Condensed","role":"heading"}],"colors":{"primary":"#E8423B","secondary":"#40A9FF","accent":"#E8423B","background":"#FFFFFF","textPrimary":"#313130","link":"#3858E9"},"typography":{"fontFamilies":{"primary":"Inter","heading":"Roboto Condensed"},"fontStacks":{"heading":["Inter","sans-serif"],"body":["Times New Roman"],"paragraph":["Inter","sans-serif"]},"fontSizes":{"h1":"92.16px","h2":"92.16px","body":"20.736px"}},"spacing":{"baseUnit":4,"borderRadius":"2px"},"components":{"buttonPrimary":{"background":"#FFFFFF","textColor":"#E8423B","borderRadius":"0px","borderRadiusCorners":{"topLeft":"0px","topRight":"0px","bottomRight":"0px","bottomLeft":"0px"},"shadow":"none"}},"images":{"logo":"https://www.albinigroup.com/wp-content/themes/albinigroup/static/img/logo.svg","favicon":"https://www.albinigroup.com/wp-content/themes/albinigroup/static/img/favicons/favicon.ico","ogImage":null,"logoHref":"https://www.albinigroup.com/en/","logoAlt":"Albini Group Logo"},"personality":{"tone":"professional","energy":"medium","targetAudience":"business professionals"},"designSystem":{"framework":"custom","componentLibrary":""},"confidence":{"buttons":0.8,"colors":0.9,"overall":0.8500000000000001},"brandName":"Homepage","logo":"https://www.albinigroup.com/wp-content/themes/albinigroup/static/img/logo.svg"},"metadata":{"viewport":"width=device-width, initial-scale=1","theme-color":"#060606","generator":"WPML ver:4.6.11 stt:1,27;","language":"en-US","robots":"max-image-preview:large","title":"Homepage","msapplication-TileImage":"https://www.albinigroup.com/wp-content/uploads/2024/07/android-chrome-512x512-2-300x300.png","format-detection":"telephone=no","favicon":"https://www.albinigroup.com/wp-content/themes/albinigroup/static/img/favicons/favicon.ico","scrapeId":"01a10843-3309-76f1-87e6-86b2fe6dff94","sourceURL":"https://www.albinigroup.com/en/","url":"https://www.albinigroup.com/en/","statusCode":200,"contentType":"text/html; charset=UTF-8","timezone":"America/New_York","proxyUsed":"basic","indexId":"687378ad-1338-4a4e-890d-8f67d61cc28a","creditsUsed":1,"concurrencyLimited":false}}
+1
View File
@@ -0,0 +1 @@
{"branding":{"colorScheme":"light","fonts":[{"family":"Helvetica Neue","role":"body"},{"family":"Palatino Linotype","role":"heading"}],"colors":{"primary":"#2563EB","secondary":"#9CA3AF","accent":"#2F2727","background":"#2F2727","textPrimary":"#2F2727","link":"#6B7280"},"typography":{"fontFamilies":{"primary":"Helvetica Neue","heading":"Palatino Linotype"},"fontStacks":{"heading":["__swiss_888950","__swiss_Fallback_888950","Helvetica Neue","Helvetica","Arial","sans-serif"],"body":["__swiss_888950","__swiss_Fallback_888950","Helvetica Neue","Helvetica","Arial","sans-serif"],"paragraph":["__swiss_888950","__swiss_Fallback_888950","Helvetica Neue","Helvetica","Arial","sans-serif"]},"fontSizes":{"h1":"16px","h2":"48px","body":"16px"}},"spacing":{"baseUnit":4,"borderRadius":"0px"},"components":{"input":{"background":"#FFFFFF","textColor":"#2F2727","borderColor":"#D5D4D4","borderRadius":"9999px","borderRadiusCorners":{"topLeft":"9999px","topRight":"9999px","bottomRight":"9999px","bottomLeft":"9999px"},"shadow":"none"},"buttonPrimary":{"background":"#2F2727","textColor":"#FFFFFF","borderRadius":"9999px","borderRadiusCorners":{"topLeft":"9999px","topRight":"9999px","bottomRight":"9999px","bottomLeft":"9999px"},"shadow":"none"},"buttonSecondary":{"background":"#F5F5F5","textColor":"#2F2727","borderRadius":"9999px","borderRadiusCorners":{"topLeft":"9999px","topRight":"9999px","bottomRight":"9999px","bottomLeft":"9999px"},"shadow":"none"}},"images":{"logo":"https://content.camirafabrics.com/media/2gcngglc/camira-logo-light.svg?q=100&width=3840","favicon":"https://www.camirafabrics.com/favicon.ico","ogImage":null,"logoHref":"https://www.camirafabrics.com/us?meta=JTdCJTdE","logoAlt":"Camira Logo Light"},"personality":{"tone":"professional","energy":"medium","targetAudience":"business professionals"},"designSystem":{"framework":"tailwind","componentLibrary":""},"confidence":{"buttons":0.9,"colors":0.9,"overall":0.9},"brandName":"Camira","logo":"https://content.camirafabrics.com/media/2gcngglc/camira-logo-light.svg?q=100&width=3840"},"metadata":{"robots":"noindex","viewport":["width=device-width, initial-scale=1","width=device-width,initial-scale=1"],"title":"Camira | Leading Supplier of Contract Fabrics and Upholstery Solutions","google-site-verification":"9h1IFVr9Fye0MSBgBlu-rt6V1e3C34bL0IbfI6HsTLY","description":"Discover Camira's extensive range of contract fabrics, ideal for commercial and residential interiors. Explore our high-quality upholstery solutions tailored for offices, hotels, and more","language":"en-US","favicon":"https://www.camirafabrics.com/favicon.ico","scrapeId":"01a10842-a7a3-751a-8edc-a88a06d5d185","sourceURL":"https://www.camirafabrics.com/us","url":"https://www.camirafabrics.com/us","statusCode":200,"contentType":"text/html; charset=utf-8","timezone":"America/New_York","proxyUsed":"basic","indexId":"1372bc68-234b-44eb-828a-ef652391b19a","creditsUsed":1,"concurrencyLimited":true,"concurrencyQueueDurationMs":13158},"warning":"This scrape job was throttled at your current concurrency limit. If you'd like to scrape faster, you can upgrade your plan."}
+1
View File
@@ -0,0 +1 @@
{"branding":{"colorScheme":"light","fonts":[{"family":"Kvadrat Neuzeit S","role":"body"},{"family":"Arial","role":"body"}],"colors":{"primary":"#000000","accent":"#000000","background":"#FFFFFF","textPrimary":"#231F20","link":"#000000"},"typography":{"fontFamilies":{"primary":"Kvadrat Neuzeit S","heading":"Kvadrat Neuzeit S"},"fontStacks":{"heading":["kvadrat_neuzeit_s","Arial","sans-serif"],"body":["kvadrat_neuzeit_s","Arial","sans-serif"],"paragraph":["kvadrat_neuzeit_s","Arial","sans-serif"]},"fontSizes":{"h1":"16px","h2":"25px","body":"16px"}},"spacing":{"baseUnit":8,"borderRadius":"0px"},"components":{"input":{"background":"#FFFFFF","textColor":"#231F20","borderColor":null,"borderRadius":"22.5px","borderRadiusCorners":{"topLeft":"22.5px","topRight":"22.5px","bottomRight":"22.5px","bottomLeft":"22.5px"},"shadow":"none"}},"images":{"logo":"https://www.kvadrat.dk/apple-touch-icon-180x180-precomposed.png","favicon":"https://www.kvadrat.dk/apple-touch-icon-precomposed.png","ogImage":null,"logoAlt":"Kvadrat"},"personality":{"tone":"professional","energy":"medium","targetAudience":"design professionals"},"designSystem":{"framework":"custom","componentLibrary":""},"confidence":{"buttons":0,"colors":0.9,"overall":0.45},"brandName":"Kvadrat","logo":"https://www.kvadrat.dk/apple-touch-icon-180x180-precomposed.png"},"metadata":{"title":"Kvadrat - The global design textile company","ogTitle":"Kvadrat - The global design textile company","HandheldFriendly":"true","apple-mobile-web-app-title":"Kvadrat","ogImage":"","og:type":"website","og:description":"Immerse yourself in a world of inspiring contemporary textiles with Kvadrat. Explore our elegant upholstery, captivating curtains, premium rugs, and high-quality and sustainable solutions and bring your interior projects to life.","viewport":["width=device-width, initial-scale=1.0","width=device-width,initial-scale=1,user-scalable=yes","width=device-width,initial-scale=1"],"language":"en","og:image:height":"630","googlebot":"noindex,indexifembedded","description":"Immerse yourself in a world of inspiring contemporary textiles with Kvadrat. Explore our elegant upholstery, captivating curtains, premium rugs, and high-quality and sustainable solutions and bring your interior projects to life.","mobile-web-app-capable":"yes","apple-mobile-web-app-capable":"yes","fragment":"!","apple-mobile-web-app-status-bar-style":"black","ogDescription":"Immerse yourself in a world of inspiring contemporary textiles with Kvadrat. Explore our elegant upholstery, captivating curtains, premium rugs, and high-quality and sustainable solutions and bring your interior projects to life.","robots":["index, follow","index, follow"],"og:title":"Kvadrat - The global design textile company","google-site-verification":"P2D50rlQuBWe5zCrhyaWdg25yf1EPkUj_T0QSD4Ux30","og:url":"/en","og:image:width":"1200","og:image":"","ogUrl":"/en","favicon":"https://www.kvadrat.dk/touch-icon-192x192.png","scrapeId":"01a10842-a78e-726d-8967-816fd3028c2a","sourceURL":"https://www.kvadrat.dk/en","url":"https://www.kvadrat.dk/en","statusCode":200,"contentType":"text/html; charset=utf-8","timezone":"America/New_York","proxyUsed":"basic","indexId":"88c37cd9-deae-4af8-aa23-4a7ab4e5fba9","creditsUsed":1,"concurrencyLimited":false}}
+1
View File
@@ -0,0 +1 @@
{"branding":{"colorScheme":"light","fonts":[{"family":"MaharamNeue-Medium","role":"heading"},{"family":"MaharamNeue-Regular","role":"body"}],"colors":{"primary":"#1B7F9E","secondary":"#C18610","accent":"#07893E","background":"#EDEDE8","textPrimary":"#000000","link":"#07893E"},"typography":{"fontFamilies":{"primary":"MaharamNeue-Regular","heading":"MaharamNeue-Medium"},"fontStacks":{"heading":["MaharamNeue-Regular","Helvetica","Arial","sans-serif"],"body":["MaharamNeue-Regular","Helvetica","Arial","sans-serif"],"paragraph":["MaharamNeue-Medium","Helvetica","Arial","sans-serif"]},"fontSizes":{"h1":"14px","h2":"14px","body":"9px"}},"spacing":{"baseUnit":4,"borderRadius":"4px"},"components":{"input":{"background":"#FFFFFF","textColor":"#000000","borderColor":null,"borderRadius":"5px","borderRadiusCorners":{"topLeft":"5px","topRight":"5px","bottomRight":"5px","bottomLeft":"5px"},"shadow":"none"}},"images":{"logo":"https://www.maharam.com/apple-touch-icon.png","favicon":"https://www.maharam.com/assets/favicon-f4f91d83b92be42dcd21f5946f92e54c048fba408c22f621e58c1ac167f40f61.ico","ogImage":null,"logoAlt":"Maharam"},"personality":{"tone":"professional","energy":"medium","targetAudience":"design professionals"},"designSystem":{"framework":"custom","componentLibrary":""},"confidence":{"buttons":0,"colors":0.95,"overall":0.475},"brandName":"Maharam","logo":"https://www.maharam.com/apple-touch-icon.png"},"metadata":{"robots":"follow,index","language":"en","copyright":"Copyright 2026, Maharam","description":"Maharam is North America's leading creator of textiles for commercial and residential interiors.","keywords":"Maharam, Knoll Textiles, Edelman, Textiles, Fabrics, Wallcoverings, Privacy Curtains, Window Coverings, Drapery, Draperies, Digital Projects, Maharam Digital Projects, Panel, Wall Systems, Upholstery, Commercial, Contract, Residential, Interiors, Healthcare, Hospitality, Corporate, Collaboration, Twentieth Century, Agenda, Leather, Leather Tiles, Hides","revisit-after":"3 days","msapplication-config":"none","title":"Maharam","viewport":"width=device-width, initial-scale=1, shrink-to-fit=no","csrf-param":"authenticity_token","csrf-token":"RGnSJ-2JJQtSeKNBhGhi83R4MK-_INpAFYbIJ3oTKb8mZhGaapWN5MaGCQbFdeuvqDUnDre-FVlo80aieCFOWQ","favicon":"https://www.maharam.com/assets/favicon-f4f91d83b92be42dcd21f5946f92e54c048fba408c22f621e58c1ac167f40f61.ico","scrapeId":"01a10842-a79d-771c-ad1e-215713ca4db4","sourceURL":"https://www.maharam.com/","url":"https://www.maharam.com/","statusCode":200,"contentType":"text/html; charset=utf-8","timezone":"America/New_York","proxyUsed":"basic","indexId":"f1f9c1aa-aeeb-4a2b-950e-cd5df6f4530f","creditsUsed":1,"concurrencyLimited":true,"concurrencyQueueDurationMs":6122},"warning":"This scrape job was throttled at your current concurrency limit. If you'd like to scrape faster, you can upgrade your plan."}
+1
View File
@@ -0,0 +1 @@
{"branding":{"colorScheme":"light","fonts":[{"family":"Noto Sans","role":"body"}],"colors":{"primary":"#00378C","secondary":"#0D6EFD","accent":"#00378C","background":"#FFFFFF","textPrimary":"#000000","link":"#003366"},"typography":{"fontFamilies":{"primary":"Noto Sans","heading":"Noto Sans"},"fontStacks":{"heading":["Noto Sans","sans-serif"],"body":["Noto Sans","sans-serif"],"paragraph":["Noto Sans","sans-serif"]},"fontSizes":{"h1":"48px","h2":"48px","body":"20px"}},"spacing":{"baseUnit":4,"borderRadius":"3px"},"components":{"buttonPrimary":{"background":"#00378C","textColor":"#FFFFFF","borderColor":"#00378C","borderRadius":"50px","borderRadiusCorners":{"topLeft":"50px","topRight":"50px","bottomRight":"50px","bottomLeft":"50px"},"shadow":"none"},"buttonSecondary":{"background":"#000000","textColor":"#FFFFFF","borderRadius":"0px","borderRadiusCorners":{"topLeft":"0px","topRight":"0px","bottomRight":"0px","bottomLeft":"0px"},"shadow":"none"}},"images":{"logo":"https://www.milliken.com/-/media/milliken/footer-v2/milliken-logo-footer.svg","favicon":"https://www.milliken.com/assets/images/favicons/milliken-favicon.ico","ogImage":"https://contenthub.milliken.com/api/public/content/142bbadfbf6c4309a5b627a101800bac?v=eaf7ac01&t=W1440xH720","logoHref":"https://www.milliken.com/en-us/","logoAlt":"Milliken & Company logo"},"personality":{"tone":"professional","energy":"medium","targetAudience":"business professionals and industries seeking high-performance textiles"},"designSystem":{"framework":"bootstrap","componentLibrary":""},"confidence":{"buttons":0.95,"colors":0.9,"overall":0.925},"brandName":"High","logo":"https://www.milliken.com/-/media/milliken/footer-v2/milliken-logo-footer.svg"},"metadata":{"description":"Discover Milliken’s high-performance textiles for apparel, automotive, military, and industrial markets engineered through material science and PFAS-free innovation.","ogTitle":"High-Performance Textiles & Fabric Innovation | Milliken","viewport":"width=device-width, initial-scale=1, shrink-to-fit=no","title":"High-Performance Textiles & Fabric Innovation | Milliken","facebook-domain-verification":"bb8bw417fkjl8mfe669ii98qp9i87s","og:title":"High-Performance Textiles & Fabric Innovation | Milliken","language":"en-US","og:description":"Discover","ogDescription":"Discover","keywords":"","ogUrl":"https://www.milliken.com/en-us/textiles","og:type":"website","og:image:height":"660","og:image:width":"1920","ogImage":"https://contenthub.milliken.com/api/public/content/142bbadfbf6c4309a5b627a101800bac?v=eaf7ac01&t=W1440xH720","og:image:alt":"Flame resist fabric testing with dummy being exposed to flames","og:url":"https://www.milliken.com/en-us/textiles","og:image":"https://contenthub.milliken.com/api/public/content/142bbadfbf6c4309a5b627a101800bac?v=eaf7ac01&t=W1440xH720","favicon":"https://www.milliken.com/assets/images/favicons/milliken-favicon.ico","scrapeId":"01a10843-32fe-73b8-b81f-534572f9f400","sourceURL":"https://textiles.milliken.com/","url":"https://www.milliken.com/en-us/textiles","statusCode":200,"contentType":"text/html; charset=utf-8","timezone":"America/New_York","proxyUsed":"basic","indexId":"bd4adbc8-3a41-484e-a57a-d8832a065cce","creditsUsed":1,"concurrencyLimited":false}}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 161 KiB

+3 -162
View File
@@ -10,8 +10,7 @@
"dependencies": {
"react": "^19.1.0",
"react-dom": "^19.1.0",
"react-router-dom": "^7.6.0",
"vgpu": "^0.5.0"
"react-router-dom": "^7.6.0"
},
"devDependencies": {
"@playwright/test": "^1.52.0",
@@ -793,31 +792,6 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
"node_modules/@modelcontextprotocol/core": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/core/-/core-2.0.0.tgz",
"integrity": "sha512-pJCEwGG7Lfr/+PQp9ZTwKXNeO5wzbfKL7H3MYpCorM4oFBoQrdjnBgEoqG+RjhsvS1FKrDbKux+M1HhlnGWqcA==",
"license": "MIT",
"dependencies": {
"zod": "^4.2.0"
},
"engines": {
"node": ">=20"
}
},
"node_modules/@modelcontextprotocol/server": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/server/-/server-2.0.0.tgz",
"integrity": "sha512-YhHWdHfpFMQfd0prsEnxKeS3Qz3ytIGmsS0sth4KDjnacIT7hxk6hXHkJ9KysxlkvTM+WZAtQbbcUhdoP4Hvtw==",
"license": "MIT",
"dependencies": {
"@modelcontextprotocol/core": "2.0.0",
"zod": "^4.2.0"
},
"engines": {
"node": ">=20"
}
},
"node_modules/@napi-rs/lzma-linux-x64-gnu": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/@napi-rs/lzma-linux-x64-gnu/-/lzma-linux-x64-gnu-1.5.1.tgz",
@@ -1302,58 +1276,6 @@
"dev": true,
"license": "MIT"
},
"node_modules/@vgpu/adapter-mock": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/@vgpu/adapter-mock/-/adapter-mock-0.5.0.tgz",
"integrity": "sha512-YtgXOFn1qI+8oTJenG2wWbQPA28V0CfE5UJs5Xqbt6qyR/xaZ5LHH2XWTwFcjnqn2b1xQCyTatJCMyyOdweUnw==",
"license": "MIT",
"dependencies": {
"@vgpu/core": "0.5.0"
}
},
"node_modules/@vgpu/adapter-node": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/@vgpu/adapter-node/-/adapter-node-0.5.0.tgz",
"integrity": "sha512-lgzqFcLDejwRgwlaNStzkwLNU9b4aN2OoPpWqT1UyPmK521BSw2OIQKzAuDIkzNlREla6KNC12G6bthhOzZKzw==",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
"@vgpu/core": "0.5.0",
"webgpu": "0.4.0"
}
},
"node_modules/@vgpu/core": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/@vgpu/core/-/core-0.5.0.tgz",
"integrity": "sha512-z80DHRHViv6+FKKkPzggEtT1ZZs/WCKRQbzJuwYdA135DZaSbCMoRK4anhM+I/nOHuDpf7H3xjkwE6rfolWZUw==",
"license": "MIT",
"dependencies": {
"@vgpu/wgsl": "0.5.0"
}
},
"node_modules/@vgpu/wgsl": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/@vgpu/wgsl/-/wgsl-0.5.0.tgz",
"integrity": "sha512-PDlDJem7J28C9bk+vPy2kYZEoW8+nYIx2oN4nu7/WF2V7ETx32BtmWcawwMbhiu/CVsobFafML0h0eqLRBNa3Q==",
"license": "MIT",
"dependencies": {
"@vgpu/wgsl-std": "0.5.0"
},
"peerDependencies": {
"@vgpu/adapter-node": ">=0.1.6 <1.0.0 || ^0.5.0-rc.0"
},
"peerDependenciesMeta": {
"@vgpu/adapter-node": {
"optional": true
}
}
},
"node_modules/@vgpu/wgsl-std": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/@vgpu/wgsl-std/-/wgsl-std-0.5.0.tgz",
"integrity": "sha512-NjMyJxwy4evFNCSqFQy4EqAbZ7iU+NUyJYyG9tLUhbdDLzBmfZlk1S3PyRZ9olBFFfEiVW2JNVw10maPKLEs1A==",
"license": "MIT"
},
"node_modules/@vitejs/plugin-react": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz",
@@ -1375,12 +1297,6 @@
"vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0"
}
},
"node_modules/@webgpu/types": {
"version": "0.1.72",
"resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.72.tgz",
"integrity": "sha512-0cF7RFM2edNoiIS1ODJp0/Gzv4/xSXhwoR0YCza+OWpJWtn4wmo9DvK91aLlH9+uUnwIriP7ZiC3WitmyhuzBw==",
"license": "BSD-3-Clause"
},
"node_modules/baseline-browser-mapping": {
"version": "2.11.21",
"resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.21.tgz",
@@ -1473,6 +1389,7 @@
"version": "4.4.3",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
"dev": true,
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
@@ -1635,6 +1552,7 @@
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"dev": true,
"license": "MIT"
},
"node_modules/nanoid": {
@@ -1686,18 +1604,6 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/pixelmatch": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-7.2.0.tgz",
"integrity": "sha512-xhcb4yHu9sM/G7foGzoLtXYcC0zHEaOXXjRKhGup0fw78Nf2Tkiapv4EQyMzrbcmQPsllAI7DbFY2UT7PlI9Pg==",
"license": "ISC",
"dependencies": {
"pngjs": "^7.0.0"
},
"bin": {
"pixelmatch": "bin/pixelmatch"
}
},
"node_modules/playwright": {
"version": "1.63.0",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.63.0.tgz",
@@ -1727,15 +1633,6 @@
"node": ">=20"
}
},
"node_modules/pngjs": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/pngjs/-/pngjs-7.0.0.tgz",
"integrity": "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==",
"license": "MIT",
"engines": {
"node": ">=14.19.0"
}
},
"node_modules/postcss": {
"version": "8.5.28",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.28.tgz",
@@ -1960,36 +1857,6 @@
"browserslist": ">= 4.21.0"
}
},
"node_modules/vgpu": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/vgpu/-/vgpu-0.5.0.tgz",
"integrity": "sha512-isQfMHRTysYFfT8UWTzqQI/ROw2L7lVkj7xoUJlvIF6FjYxBNS/YNG7qp3tZ7ZvZZ3uwYjso+geQv/bEq5Hl3w==",
"license": "MIT",
"dependencies": {
"@modelcontextprotocol/server": "2.0.0",
"@vgpu/adapter-mock": "0.5.0",
"@vgpu/adapter-node": "0.5.0",
"@vgpu/core": "0.5.0",
"@vgpu/wgsl": "0.5.0",
"@vgpu/wgsl-std": "0.5.0",
"@webgpu/types": "^0.1.69",
"pixelmatch": "^7.2.0",
"pngjs": "^7.0.0",
"wgpu-matrix": "^3.4.2",
"zod": "^4.4.3"
},
"bin": {
"vgpu": "bin/vgpu.js"
},
"peerDependencies": {
"three": ">=0.180.0 <0.200.0"
},
"peerDependenciesMeta": {
"three": {
"optional": true
}
}
},
"node_modules/vite": {
"version": "6.4.3",
"resolved": "https://registry.npmjs.org/vite/-/vite-6.4.3.tgz",
@@ -2065,38 +1932,12 @@
}
}
},
"node_modules/webgpu": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/webgpu/-/webgpu-0.4.0.tgz",
"integrity": "sha512-F5pimn3Aoi0zWjuRdiVs5TnrUwSzD2lESBohsIUsqyitWkGRQlXU2fhV6ycXlQTa1bvAf3sjqiUpBEpmSQ5ptA==",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
"@webgpu/types": "^0.1.69",
"debug": "^4.4.0"
}
},
"node_modules/wgpu-matrix": {
"version": "3.4.2",
"resolved": "https://registry.npmjs.org/wgpu-matrix/-/wgpu-matrix-3.4.2.tgz",
"integrity": "sha512-IfZFbG7olEYBD76VCZy2TzqM57GKy3LT++AZh37tMHPPByO6R2h61zXGBZFNPi2IzxNivNi8y5dvze5PjaczjA==",
"license": "MIT"
},
"node_modules/yallist": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
"dev": true,
"license": "ISC"
},
"node_modules/zod": {
"version": "4.6.5",
"resolved": "https://registry.npmjs.org/zod/-/zod-4.6.5.tgz",
"integrity": "sha512-v5l/aFXZQeai4awLbOpSoHecE9UiMrnfx75tEXLjNonXVARxQ5mOeipTjROUchszUNCqnE+hqAMujRsRHsut2Q==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
}
}
}
+1 -2
View File
@@ -12,8 +12,7 @@
"dependencies": {
"react": "^19.1.0",
"react-dom": "^19.1.0",
"react-router-dom": "^7.6.0",
"vgpu": "^0.5.0"
"react-router-dom": "^7.6.0"
},
"devDependencies": {
"@playwright/test": "^1.52.0",
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,93 +1,93 @@
Copyright 2014 The DM Sans Project Authors (https://github.com/googlefonts/dm-fonts)
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
https://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
Copyright 2022 The Noto Project Authors (https://github.com/notofonts/latin-greek-cyrillic) NotoSans-Italic[wdth,wght].ttf: Copyright 2022 The Noto Project Authors (https://github.com/notofonts/latin-greek-cyrillic)
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
Binary file not shown.
@@ -1,8 +1,8 @@
Copyright 2022 The Instrument Serif Project Authors (https://github.com/Instrument/instrument-serif)
Copyright 2011 Google Inc. All Rights Reserved. RobotoCondensed-Italic[wght].ttf: Copyright 2011 Google Inc. All Rights Reserved.
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
https://scripts.sil.org/OFL
http://scripts.sil.org/OFL
-----------------------------------------------------------
@@ -18,7 +18,7 @@ with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 161 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 KiB

+14 -15
View File
@@ -1,21 +1,14 @@
@font-face {
font-family: "Instrument Serif";
src: url("/fonts/instrument-serif-regular.ttf") format("truetype");
font-weight: 400;
font-family: "Roboto Condensed";
src: url("/fonts/roboto-condensed.woff2") format("woff2");
font-weight: 100 900;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "Instrument Serif";
src: url("/fonts/instrument-serif-italic.ttf") format("truetype");
font-weight: 400;
font-style: italic;
font-display: swap;
}
@font-face {
font-family: "DM Sans";
src: url("/fonts/dm-sans.woff2") format("woff2");
font-weight: 100 1000;
font-family: "Noto Sans";
src: url("/fonts/noto-sans.woff2") format("woff2");
font-weight: 100 900;
font-style: normal;
font-display: swap;
}
@@ -26,8 +19,10 @@
--line: #d9d9cf;
--wash: #ecebe4;
--accent: #8f725c;
--serif: "Instrument Serif", Georgia, serif;
--sans: "DM Sans", Arial, sans-serif;
--industrial: #496678;
--industrial-deep: #273f4d;
--serif: "Roboto Condensed", "Arial Narrow", sans-serif;
--sans: "Noto Sans", Arial, sans-serif;
--mono: "Courier New", monospace;
--page-gutter: clamp(20px, 4vw, 72px);
color-scheme: light;
@@ -48,6 +43,10 @@ body {
margin: 0;
min-width: 320px;
}
em {
font-style: normal;
font-weight: 600;
}
button,
input,
textarea,
+7 -5
View File
@@ -10,13 +10,15 @@ export default function Gallery({ preview = false }) {
<section className="gallery" id="developments" tabIndex={-1}>
<SectionHeading
centered
label="Selected developments"
label={
preview ? "Featured fabric developments" : "Selected developments"
}
title={
preview ? (
<>
Structure changes
What we make.
<br />
<em>everything.</em>
<em>What we can develop.</em>
</>
) : (
<>
@@ -29,12 +31,12 @@ export default function Gallery({ preview = false }) {
>
<p className="gallery__intro">
{preview
? "From subtle surface structures to more expressive knitted textures, different yarn combinations and machine setups produce entirely different fabric characteristics."
? "A selection of knitted structures showing how yarn, composition and machine setup shape the final fabric character."
: "Selected developments are processed separately as reference samples to explore how a construction can translate after dyeing and finishing. RRS commercially manufactures greige fabric only."}
</p>
{preview && (
<Action to="/fabrics#developments" variant="outline">
View developments
Explore all fabrics
</Action>
)}
</SectionHeading>
+13 -30
View File
@@ -31,7 +31,9 @@
top: 10px;
}
.site-header {
border-top: 4px solid var(--industrial);
border-bottom: 1px solid var(--line);
background: #faf9f5;
}
.site-header__inner {
display: flex;
@@ -44,27 +46,11 @@
.brand {
display: inline-flex;
align-items: center;
gap: 16px;
text-decoration: none;
color: var(--ink);
}
.brand__mark {
font-family: var(--serif);
font-size: 42px;
font-weight: 600;
line-height: 1;
letter-spacing: -0.065em;
}
.brand__period {
color: var(--accent);
}
.brand__name {
border-left: 1px solid var(--line);
padding-left: 16px;
font-size: 9px;
line-height: 1.65;
text-transform: uppercase;
letter-spacing: 0.12em;
.brand__logo {
display: block;
width: 92px;
height: auto;
}
.site-nav {
display: flex;
@@ -100,15 +86,15 @@
gap: 30px;
margin-left: 45px;
padding: 12px 20px;
border: 1px solid var(--ink);
border: 1px solid var(--industrial-deep);
border-radius: 30px;
color: var(--ink);
background: var(--industrial-deep);
color: var(--paper);
text-decoration: none;
font-size: 11px;
}
.site-nav__contact:hover {
background: var(--ink);
color: var(--paper);
background: var(--industrial);
}
.site-header__toggle {
display: none;
@@ -209,7 +195,7 @@
display: flex;
align-items: center;
min-height: 420px;
background: var(--ink);
background: var(--industrial-deep);
color: var(--paper);
padding: 64px;
border-radius: 6px;
@@ -282,11 +268,8 @@
flex-wrap: wrap;
gap: 0;
}
.brand__mark {
font-size: 35px;
}
.brand__name {
font-size: 8px;
.brand__logo {
width: 78px;
}
.site-header__toggle {
display: flex;
+9 -10
View File
@@ -7,14 +7,13 @@ import "./Layout.css";
function Brand() {
return (
<Link className="brand" to="/" aria-label="RRS home">
<span className="brand__mark">
RRS<span className="brand__period">.</span>
</span>
<span className="brand__name">
Radhe Radhe
<br />
Synthetics
</span>
<img
className="brand__logo"
src="/images/RRSLOGO.png"
alt="Radhe Radhe Synthetics"
width="1024"
height="809"
/>
</Link>
);
}
@@ -68,7 +67,7 @@ function Header() {
to="/contact#whatsapp"
onClick={closeMenu}
>
Let's talk <Arrow diagonal />
Request a quote <Arrow diagonal />
</Link>
</nav>
</div>
@@ -93,7 +92,7 @@ function Footer() {
))}
</nav>
<div className="site-footer__contact">
<span className="site-footer__label">Start a conversation</span>
<span className="site-footer__label">Commercial enquiries</span>
<Link className="site-footer__link" to="/contact#whatsapp">
WhatsApp <Arrow diagonal />
</Link>
+185 -62
View File
@@ -2,76 +2,124 @@
position: fixed;
inset: 0;
z-index: 1000;
display: grid;
grid-template-rows: auto 1fr;
overflow: hidden;
padding: clamp(24px, 3.5vw, 56px);
color: #f5f3ee;
background: #24231e;
transition:
opacity 650ms cubic-bezier(0.76, 0, 0.24, 1),
clip-path 650ms cubic-bezier(0.76, 0, 0.24, 1);
clip-path: inset(0);
color: var(--ink);
background: var(--paper);
}
.loader--closing {
opacity: 0;
clip-path: inset(0 0 100% 0);
pointer-events: none;
}
.loader__canvas,
.loader__veil {
.loader__scene {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
}
.loader__canvas {
display: block;
opacity: 0;
transition: opacity 180ms ease-out;
}
.loader__canvas[data-ready="true"] {
opacity: 1;
}
.loader__veil {
background: linear-gradient(90deg, #17171238, transparent 45%, #17171238);
}
.loader__topline,
.loader__center {
position: relative;
.loader__yarns {
position: absolute;
z-index: 1;
top: 0;
left: 50%;
width: min(72vw, 920px);
height: 34%;
overflow: visible;
transform: translateX(-50%);
}
.loader__topline {
.loader__yarns path {
fill: none;
stroke: var(--industrial);
stroke-width: 5;
stroke-linecap: round;
vector-effect: non-scaling-stroke;
opacity: 0;
stroke-dasharray: 1200;
stroke-dashoffset: 1200;
animation: yarn-feed 780ms 480ms cubic-bezier(0.22, 1, 0.36, 1) forwards;
}
.loader__yarns path:nth-child(2),
.loader__yarns path:nth-child(6) {
stroke: var(--accent);
animation-delay: 580ms;
}
.loader__yarns path:nth-child(3),
.loader__yarns path:nth-child(5) {
animation-delay: 660ms;
}
.loader__yarns path:nth-child(4) {
stroke: var(--ink);
stroke-width: 6;
animation-delay: 540ms;
}
.loader__machine {
position: absolute;
z-index: 2;
inset: 5% 0 7%;
display: grid;
place-items: center;
clip-path: inset(0 0 100%);
animation: machine-reveal 900ms 680ms cubic-bezier(0.22, 1, 0.36, 1) forwards;
}
.loader__machine-image {
display: block;
width: auto;
height: min(84vh, 1050px);
max-width: 84vw;
object-fit: contain;
filter: grayscale(1) contrast(1.08);
transform: scale(1.04);
animation: machine-colour 850ms 1050ms ease-out forwards;
}
.loader__brand {
position: absolute;
z-index: 4;
left: 50%;
bottom: clamp(18px, 2.2vw, 36px);
display: flex;
align-items: center;
justify-content: space-between;
gap: 18px;
font-size: 10px;
font-weight: 600;
letter-spacing: 0.16em;
text-transform: uppercase;
padding: 10px 18px;
border: 1px solid #282a2324;
border-radius: 999px;
background: #f5f3eee8;
backdrop-filter: blur(8px);
opacity: 0;
transform: translate(-50%, 14px);
animation: brand-arrive 450ms 1500ms ease-out forwards;
}
.loader__center {
align-self: center;
justify-self: center;
text-align: center;
.loader__logo {
width: 82px;
height: auto;
}
.loader__eyebrow {
margin: 0 0 18px;
font-size: 11px;
letter-spacing: 0.14em;
text-transform: uppercase;
}
.loader__title {
.loader__message {
margin: 0;
padding-left: 18px;
border-left: 1px solid var(--line);
font-family: var(--serif);
font-size: clamp(58px, 8.5vw, 132px);
font-weight: 400;
line-height: 0.84;
letter-spacing: -0.055em;
font-size: 18px;
line-height: 1.1;
white-space: nowrap;
}
.loader__title em {
font-weight: 400;
.loader__handoff {
position: absolute;
z-index: 10;
inset: 0;
background:
repeating-linear-gradient(115deg, transparent 0 8px, #f5f3ee13 8px 9px),
var(--industrial-deep);
transform: translateX(-101%);
will-change: transform;
}
.loader--covering {
pointer-events: none;
}
.loader--covering .loader__handoff {
animation: handoff-cover 450ms cubic-bezier(0.76, 0, 0.24, 1) forwards;
}
.loader--revealing {
background: transparent;
pointer-events: none;
}
.loader--revealing .loader__scene {
opacity: 0;
}
.loader--revealing .loader__handoff {
transform: translateX(0);
animation: handoff-reveal 600ms cubic-bezier(0.76, 0, 0.24, 1) forwards;
}
.loader__announcement {
position: absolute;
@@ -81,16 +129,91 @@
clip-path: inset(50%);
white-space: nowrap;
}
@media (max-width: 600px) {
.loader__title {
font-size: clamp(54px, 19vw, 86px);
@keyframes yarn-feed {
0% {
opacity: 0;
stroke-dashoffset: 1200;
}
.loader__topline span:last-child {
display: none;
4% {
opacity: 0.82;
}
100% {
opacity: 0.82;
stroke-dashoffset: 0;
}
}
@keyframes machine-reveal {
to {
clip-path: inset(0);
}
}
@keyframes machine-colour {
to {
filter: grayscale(0) contrast(1);
transform: scale(1);
}
}
@keyframes brand-arrive {
to {
opacity: 1;
transform: translate(-50%, 0);
}
}
@keyframes handoff-cover {
to {
transform: translateX(0);
}
}
@keyframes handoff-reveal {
to {
transform: translateX(101%);
}
}
@media (max-width: 600px) {
.loader__yarns {
width: 108vw;
height: 32%;
}
.loader__machine {
inset: 9% 0 12%;
}
.loader__machine-image {
width: 98vw;
height: auto;
max-width: none;
}
.loader__brand {
bottom: 22px;
gap: 11px;
padding: 8px 12px;
}
.loader__logo {
width: 66px;
}
.loader__message {
padding-left: 11px;
font-size: 15px;
}
}
@media (prefers-reduced-motion: reduce) {
.loader {
transition: none;
.loader__yarns,
.loader__handoff {
display: none;
}
.loader__machine,
.loader__machine-image,
.loader__brand {
animation: none;
}
.loader__machine {
clip-path: inset(0);
}
.loader__machine-image {
filter: none;
transform: none;
}
.loader__brand {
opacity: 1;
transform: translate(-50%, 0);
}
}
+46 -80
View File
@@ -1,106 +1,72 @@
import { useEffect, useRef, useState } from "react";
import weaveShader from "../shaders/loader.wgsl?raw";
import { useEffect, useState } from "react";
import "./Loader.css";
export default function Loader() {
const canvasRef = useRef(null);
const [phase, setPhase] = useState("active");
useEffect(() => {
const reducedMotion = window.matchMedia(
"(prefers-reduced-motion: reduce)",
).matches;
const closeTimer = window.setTimeout(
() => setPhase("closing"),
reducedMotion ? 0 : 1900,
const coveringTimer = window.setTimeout(
() => setPhase("covering"),
reducedMotion ? 0 : 2100,
);
const revealTimer = window.setTimeout(
() => setPhase("revealing"),
reducedMotion ? 25 : 2550,
);
const removeTimer = window.setTimeout(
() => setPhase("hidden"),
reducedMotion ? 50 : 2550,
reducedMotion ? 50 : 3150,
);
return () => {
window.clearTimeout(closeTimer);
window.clearTimeout(coveringTimer);
window.clearTimeout(revealTimer);
window.clearTimeout(removeTimer);
};
}, []);
useEffect(() => {
if (phase !== "active") return undefined;
let active = true;
let gpu;
let loop;
let unsubscribeResize;
async function renderWeave() {
try {
const { clock, effect, frameLoop, init, surface } = await import(
"vgpu"
);
gpu = await init({ powerPreference: "low-power" });
if (!active) return gpu.dispose();
const target = surface(gpu, canvasRef.current, { dpr: [1, 1.5] });
const weave = effect(gpu, weaveShader, {
set: { params: { time: 0, progress: 0, aspect: 1, padding: 0 } },
});
const timer = clock(gpu);
unsubscribeResize = target.onResize(({ width, height }) => {
weave.set({ params: { aspect: width / height } });
});
let presented = false;
loop = frameLoop(
gpu,
(frame) => {
weave.set({
params: {
time: timer.time,
progress: Math.min(1.2, timer.time / 1.8),
},
});
frame.pass(target, weave);
if (!presented) {
presented = true;
requestAnimationFrame(() => {
if (active) canvasRef.current.dataset.ready = "true";
});
}
},
{ fps: 30 },
);
} catch {
// A flat background remains when WebGPU is unavailable.
}
}
if (!window.matchMedia("(prefers-reduced-motion: reduce)").matches)
renderWeave();
return () => {
active = false;
loop?.stop();
unsubscribeResize?.();
gpu?.dispose();
};
}, [phase]);
if (phase === "hidden") return null;
return (
<div className={`loader loader--${phase}`} aria-live="polite">
<canvas className="loader__canvas" ref={canvasRef} aria-hidden="true" />
<div className="loader__veil" aria-hidden="true" />
<div className="loader__topline">
<span>RRS / 1987</span>
<span>Surat, India</span>
</div>
<div className="loader__center">
<p className="loader__eyebrow">Preparing the loom</p>
<p className="loader__title">
From yarn
<br />
<em>to structure.</em>
</p>
<div className="loader__scene">
<svg
className="loader__yarns"
viewBox="0 0 1000 430"
preserveAspectRatio="none"
aria-hidden="true"
>
<path pathLength="1" d="M60 0 C90 150 120 285 180 430" />
<path pathLength="1" d="M205 0 C230 155 255 310 285 430" />
<path pathLength="1" d="M350 0 C365 170 380 320 395 430" />
<path pathLength="1" d="M500 0 L500 430" />
<path pathLength="1" d="M650 0 C635 170 620 320 605 430" />
<path pathLength="1" d="M795 0 C770 155 745 310 715 430" />
<path pathLength="1" d="M940 0 C910 150 880 285 820 430" />
</svg>
<div className="loader__machine" aria-hidden="true">
<img
className="loader__machine-image"
src="/images/knitting-machine.webp"
alt=""
width="1113"
height="1316"
/>
</div>
<div className="loader__brand">
<img
className="loader__logo"
src="/images/RRSLOGO.png"
alt="Radhe Radhe Synthetics"
width="1024"
height="809"
/>
<p className="loader__message">From yarn to repeat production.</p>
</div>
</div>
<div className="loader__handoff" aria-hidden="true" />
<span className="loader__announcement">
Loading Radhe Radhe Synthetics
</span>
+3 -3
View File
@@ -3,8 +3,8 @@
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 32px;
border-block: 1px solid var(--line);
padding: 42px 0;
margin-top: 78px;
padding: 38px 0 42px;
margin-top: 42px;
}
.stats__item {
min-width: 0;
@@ -14,7 +14,7 @@
font-size: 13px;
font-weight: 500;
line-height: 1.6;
color: var(--muted);
color: var(--industrial);
}
.stats__value {
font-family: var(--serif);
+15 -10
View File
@@ -12,25 +12,30 @@ export const company = Object.freeze({
export const navigation = [
{ to: "/", label: "Home" },
{ to: "/fabrics", label: "Fabrics" },
{ to: "/about", label: "About" },
{ to: "/about", label: "Manufacturing" },
{ to: "/contact", label: "Contact" },
];
export const capabilities = [
{
title: "Develop",
subtitle: "Continuous fabric development",
text: "Different structures call for different yarns, blends and machine configurations. RRS continually develops new knitted constructions for evolving apparel requirements.",
title: "01 · Develop",
subtitle: "Define the construction",
text: "The requirement begins with the intended application, yarn, blend, structure and fabric character.",
},
{
title: "Repeat",
subtitle: "Consistency in bulk production",
text: "A successful development must remain dependable when production scales. RRS focuses on maintaining repeatability and quality across bulk manufacturing.",
title: "02 · Configure",
subtitle: "Match yarn to machine",
text: "Machine configuration and yarn selection are aligned to the construction being developed.",
},
{
title: "Manufacture",
subtitle: "Extensive circular-knitting capability",
text: "A broad range of circular-knitting configurations allows RRS to work across different structures, materials and fabric characteristics.",
title: "03 · Manufacture",
subtitle: "Circular knitting at scale",
text: "The approved construction moves into greige production across the appropriate circular-knitting setup.",
},
{
title: "04 · Repeat",
subtitle: "Maintain bulk consistency",
text: "Successful developments are reproduced with repeatability across commercial manufacturing quantities.",
},
];
+5 -5
View File
@@ -81,12 +81,12 @@ export default function About() {
return (
<>
<PageHero
label="About RRS"
label="Manufacturing at RRS"
title={
<>
Built around
<br />
<em>the fabric.</em>
<em>repeatable production.</em>
</>
}
>
@@ -100,12 +100,12 @@ export default function About() {
<section className="philosophy">
<SectionHeading
centered
label="Our philosophy"
label="Our manufacturing discipline"
title={
<>
Consistency
Develop with curiosity.
<br />
<em>and curiosity.</em>
<em>Produce with consistency.</em>
</>
}
>
+5 -5
View File
@@ -52,19 +52,19 @@ export default function Contact() {
return (
<>
<PageHero
label="Contact RRS"
label="Request a quote"
title={
<>
Let’s talk
Bring us your
<br />
<em>fabric.</em>
<em>fabric requirement.</em>
</>
}
texture="structured"
>
<p>
Whether you’re discussing an existing requirement, bulk production or
a new fabric construction, connect directly with RRS.
Share an existing requirement, bulk quantity or new construction with
RRS and begin a direct manufacturing conversation.
</p>
</PageHero>
<section className="whatsapp" id="whatsapp" tabIndex={-1}>
+19 -12
View File
@@ -4,9 +4,8 @@
flex-direction: column;
justify-content: center;
overflow: hidden;
min-height: 590px;
margin-top: 24px;
border-radius: 7px;
min-height: 768px;
margin-inline: calc(0px - var(--page-gutter));
color: var(--paper);
background: var(--ink);
}
@@ -21,11 +20,14 @@
.home-hero__shade {
position: absolute;
inset: 0;
background: #1419108f;
background:
linear-gradient(90deg, #132630e8 0%, #1f3239a8 54%, #17262f73 100%),
linear-gradient(0deg, #111b22b5 0%, transparent 45%);
}
.home-hero__content {
position: relative;
z-index: 1;
max-width: 900px;
padding: 65px 62px 90px;
}
.home-hero__title {
@@ -51,8 +53,8 @@
.home-hero__bottom {
position: absolute;
bottom: 0;
left: 32px;
right: 32px;
left: var(--page-gutter);
right: var(--page-gutter);
display: flex;
justify-content: space-between;
gap: 20px;
@@ -128,6 +130,9 @@
padding: 58px 0;
border-bottom: 1px solid var(--line);
}
.process__item:nth-child(even) {
background: linear-gradient(90deg, transparent, #49667808, transparent);
}
.process__item:nth-child(even) .process__visual {
order: -1;
}
@@ -137,9 +142,12 @@
}
.process__verb {
margin: 0 0 24px;
font-size: 14px;
font-family: var(--mono);
font-size: 11px;
font-weight: 500;
color: var(--muted);
color: var(--industrial);
letter-spacing: 0.05em;
text-transform: uppercase;
}
.process__title {
margin: 0 0 22px;
@@ -175,19 +183,18 @@
}
@media (max-width: 760px) {
.home-hero {
margin-top: 18px;
min-height: 560px;
}
.home-hero__content {
padding: 42px 26px 130px;
padding: 42px var(--page-gutter) 130px;
}
.home-hero__title {
font-size: clamp(44px, 8.9vw, 68px);
margin-top: 32px;
}
.home-hero__bottom {
left: 26px;
right: 26px;
left: var(--page-gutter);
right: var(--page-gutter);
flex-direction: column;
gap: 8px;
padding: 15px 0;
+23 -31
View File
@@ -1,35 +1,22 @@
import { Link } from "react-router-dom";
import { capabilities, company } from "../data";
import { capabilities } from "../data";
import {
Action,
Arrow,
Eyebrow,
SectionHeading,
Textile,
WhatsAppAction,
} from "../components/Primitives";
import { ContactBanner } from "../components/Layout";
import Gallery from "../components/Gallery";
import Stats from "../components/Stats";
import "./Home.css";
const processItems = [
{
...capabilities[0],
image: "fine",
href: "/fabrics#developments",
},
{
...capabilities[2],
image: "structured",
href: "/fabrics#circular-knitting",
},
{
...capabilities[1],
image: "natural",
href: "/fabrics#production",
},
];
const processItems = capabilities.map((capability, index) => ({
...capability,
image: ["fine", "natural", "structured", "fine"][index],
href: index < 2 ? "/fabrics#applications" : "/fabrics#production",
}));
export default function Home() {
return (
@@ -45,29 +32,35 @@ export default function Home() {
/>
<div className="home-hero__shade" />
<div className="home-hero__content">
<Eyebrow>Circular knitted fabrics · RRS</Eyebrow>
<Eyebrow>Specialist circular-knitting manufacturer · RRS</Eyebrow>
<h1 className="home-hero__title">
Built to develop.
<br />
<em>Built to repeat.</em>
</h1>
<p className="home-hero__description">{company.description}</p>
<p className="home-hero__description">
Greige knitted fabrics developed around yarn, structure and
application—then manufactured for consistent commercial supply.
</p>
<div className="home-hero__actions">
<Action to="/fabrics" variant="light">
Explore our fabrics
</Action>
<WhatsAppAction variant="ghost">Talk to RRS</WhatsAppAction>
<Action to="/contact#whatsapp" variant="ghost">
Request a quote
</Action>
</div>
</div>
<div className="home-hero__bottom">
<span className="home-hero__tagline">
Consistency at scale. Continuous development.
Development · Circular knitting · Bulk production
</span>
<span className="home-hero__image-note">
Illustrative texture · Photography to follow
Factory photography scheduled for content handover
</span>
</div>
</section>
<Stats />
<Gallery preview />
<section className="home-intro">
<div className="home-intro__heading">
@@ -98,21 +91,20 @@ export default function Home() {
</Link>
</div>
</section>
<Stats />
<section className="process">
<SectionHeading
label="How we work"
label="Manufacturing process"
title={
<>
Behind the fabric:
From requirement
<br />
<em>our process.</em>
<em>to repeat production.</em>
</>
}
>
<p>
Development, circular knitting and repeatable bulk production work
as one discipline.
A direct sequence connects fabric development with dependable
commercial manufacturing.
</p>
</SectionHeading>
<div className="process__list">
@@ -123,7 +115,7 @@ export default function Home() {
<h3 className="process__title">{subtitle}</h3>
<p className="process__text">{text}</p>
<Link className="process__link" to={href}>
Explore this capability <Arrow diagonal />
See our capability <Arrow diagonal />
</Link>
</div>
<Textile className="process__visual" kind={image} />
-46
View File
@@ -1,46 +0,0 @@
struct Params {
time: f32,
progress: f32,
aspect: f32,
padding: f32,
}
@group(0) @binding(0) var<uniform> params: Params;
fn thread(value: f32, width: f32) -> f32 {
return pow(0.5 + 0.5 * cos(value), width);
}
@fragment
fn fs_main(@location(0) uv: vec2f) -> @location(0) vec4f {
let p = vec2f(uv.x * params.aspect, uv.y);
let drift = sin(p.y * 18.0 + params.time * 0.42) * 0.018;
let warp = thread((p.x + drift) * 310.0, 7.0);
let weft = thread((p.y + sin(p.x * 13.0) * 0.006) * 280.0, 8.0);
let crossing = step(0.5, fract(floor(p.x * 49.0) * 0.5 + floor(p.y * 46.0) * 0.5));
let overUnder = mix(warp * 0.58 + weft, warp + weft * 0.55, crossing);
let irregularity = sin(p.x * 127.0 + sin(p.y * 31.0)) * 0.025;
let revealEdge = params.progress + sin(uv.y * 9.0 + params.time * 0.55) * 0.035;
let woven = 1.0 - smoothstep(revealEdge - 0.15, revealEdge + 0.04, uv.x);
let looseYarn = thread((p.x + sin(p.y * 8.0 + params.time) * 0.035) * 74.0, 10.0);
let wovenMask = smoothstep(0.16, 0.72, overUnder + irregularity);
let looseMask = smoothstep(0.24, 0.78, looseYarn);
let threadMask = mix(looseMask * 0.72, wovenMask, woven);
let slider = smoothstep(0.0, 1.0, params.progress);
let dyed = 1.0 - smoothstep(slider - 0.025, slider + 0.025, uv.x);
let greige = vec3f(0.69, 0.62, 0.51);
let madder = vec3f(0.72, 0.24, 0.12);
let indigo = vec3f(0.08, 0.34, 0.58);
let dyeColor = mix(madder, indigo, smoothstep(0.15, 0.9, uv.x));
let threadColor = mix(greige, dyeColor, dyed);
let shadow = vec3f(0.105, 0.10, 0.082);
let highlight = mix(vec3f(0.90, 0.84, 0.72), dyeColor * 1.35, dyed);
var color = mix(shadow, threadColor, threadMask);
color += highlight * pow(max(warp, weft), 10.0) * 0.14 * woven;
let vignette = smoothstep(0.82, 0.28, distance(uv, vec2f(0.5)));
color *= 0.7 + vignette * 0.3;
return vec4f(color, 1.0);
}
+13 -7
View File
@@ -5,7 +5,7 @@ const pages = [
["/", "Built to develop."],
["/fabrics", "Different yarns."],
["/about", "Built around"],
["/contact", "Let’s talk"],
["/contact", "Bring us your"],
];
for (const width of [1440, 768, 390, 320]) {
@@ -24,6 +24,7 @@ for (const width of [1440, 768, 390, 320]) {
heading,
);
await page.evaluate(() => document.fonts.ready);
await expect(page.locator(".loader")).toHaveCount(0, { timeout: 3500 });
for (const image of await page.locator("img").all()) {
await image.scrollIntoViewIfNeeded();
await expect(image).toHaveJSProperty("complete", true);
@@ -41,8 +42,8 @@ for (const width of [1440, 768, 390, 320]) {
(image) => !image.complete || !image.naturalWidth,
).length,
fontsLoaded:
document.fonts.check('16px "Instrument Serif"') &&
document.fonts.check('16px "DM Sans"'),
document.fonts.check('16px "Roboto Condensed"') &&
document.fonts.check('16px "Noto Sans"'),
contentWidthRatio:
document.querySelector("#main-content").getBoundingClientRect()
.width / window.innerWidth,
@@ -109,7 +110,7 @@ test("mobile navigation closes on selection and Escape", async ({ page }) => {
await toggle.click();
await page
.getByRole("navigation", { name: "Main navigation" })
.getByRole("link", { name: "About", exact: true })
.getByRole("link", { name: "Manufacturing", exact: true })
.click();
await expect(page).toHaveURL("/about");
await expect(toggle).toHaveAttribute("aria-expanded", "false");
@@ -191,7 +192,7 @@ test("every page section unveils once when scrolled into view", async ({
}
});
test("homepage feature headings are centered semantic h2 elements", async ({
test("homepage presents proof, fabrics and process in that order", async ({
page,
}) => {
await page.goto("/");
@@ -201,12 +202,17 @@ test("homepage feature headings are centered semantic h2 elements", async ({
});
const developmentsHeading = page.getByRole("heading", {
level: 2,
name: "Structure changes everything.",
name: "What we make. What we can develop.",
});
await expect(fabricsHeading).toHaveCSS("text-align", "center");
await expect(developmentsHeading.locator("..").locator("..")).toHaveClass(
/section-heading--centered/,
);
const sections = await page
.locator("#main-content > section")
.evaluateAll((nodes) => nodes.map((node) => node.classList[0]));
expect(sections.indexOf("stats")).toBeLessThan(sections.indexOf("gallery"));
expect(sections.indexOf("gallery")).toBeLessThan(sections.indexOf("process"));
});
test("capacity values roll in opposite directions and settle at 60–70", async ({
@@ -261,7 +267,7 @@ test("the woven loading page introduces the site and clears", async ({
await page.goto("/");
const loader = page.locator(".loader");
await expect(loader).toContainText("Loading Radhe Radhe Synthetics");
await expect(page.locator(".loader__canvas")).toHaveCount(1);
await expect(page.locator(".loader__machine-image")).toHaveCount(1);
await expect(loader).toHaveCount(0, { timeout: 3500 });
});