feat: add GPT Image 2.5 comparison spotlight
@@ -19,6 +19,22 @@
|
||||
<a href="./README.md">English</a> | <a href="./README.zh-CN.md">简体中文</a> | <strong>日本語</strong>
|
||||
</p>
|
||||
|
||||
## GPT Image 2.5 特集
|
||||
|
||||
[2.5 特集を見る](https://gpt-image2.canghe.ai/gpt-image-2-5/?lang=en):Sunburst と Flare を紹介し、共通プロンプト、スライダー比較、並列表示、画像拡大、生成条件の確認を通して、新旧モデルを比較する操作を体験できます。特集ページは中国語・英語に対応しています。
|
||||
|
||||
- [Sunburst](https://developers.openai.com/api/docs/models/gpt-image-2.5-sunburst):画像生成と精密な編集向け。
|
||||
- [Flare](https://developers.openai.com/api/docs/models/gpt-image-2.5-flare):高速で高品質な日常の画像生成向け。
|
||||
- **4 件の実生成例**:[532 レモン広告](https://gpt-image2.canghe.ai/gpt-image-2-5/?lang=en&case=gallery-532-test)、[527 リオのジオラマ](https://gpt-image2.canghe.ai/gpt-image-2-5/?lang=en&case=gallery-527-test)、[523 マンハッタンの水彩画](https://gpt-image2.canghe.ai/gpt-image-2-5/?lang=en&case=gallery-523-test)、[510 Bichon Shop アイコン](https://gpt-image2.canghe.ai/gpt-image-2-5/?lang=en&case=gallery-510-test)。元画像を保持し、各事例の全文プロンプトを変更せず、参照画像なしで内蔵ツールから 1 枚ずつ生成しました。ケース選択で直接切り替えられます。[画像・プロンプト・生成記録](docs/design/gpt-image-2-5/real-cases.md)。元の生成条件とツールの正確なモデル ID は未確認で、デモ例は個別に明示しています。
|
||||
|
||||
特集は独立したページです。既存の GPT-Image2 事例、テンプレート、Skill、画像生成機能を引き続き利用できます。今回の更新には 2.5 のオンライン画像生成は含まれていません。
|
||||
|
||||
<p align="center">
|
||||
<a href="https://gpt-image2.canghe.ai/gpt-image-2-5/?lang=en">
|
||||
<img src="docs/design/gpt-image-2-5/case532-preview.jpg" alt="GPT Image 2.5 特集のプレビュー:事例 532 の実生成" width="900">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
## 🌐 ビジュアル Web サイト
|
||||
|
||||
[gpt-image2.canghe.ai](https://gpt-image2.canghe.ai/) では、プロダクトとして整備された体験でギャラリーを閲覧できます。大きなプレビューの確認、プロンプト全文のコピー、スタイルやシナリオによる絞り込み、Google ログイン後の生成テスト、GitHub 上の元ケースへの移動ができます。
|
||||
|
||||
@@ -20,6 +20,22 @@
|
||||
<strong>English</strong> | <a href="./README.zh-CN.md">简体中文</a> | <a href="./README.ja.md">日本語</a>
|
||||
</p>
|
||||
|
||||
## GPT Image 2.5 Spotlight
|
||||
|
||||
[Explore the 2.5 spotlight](https://gpt-image2.canghe.ai/gpt-image-2-5/?lang=en): learn about Sunburst and Flare, then explore a shared-prompt comparison with a draggable divider, side-by-side view, image enlargement, and generation settings.
|
||||
|
||||
- [Sunburst](https://developers.openai.com/api/docs/models/gpt-image-2.5-sunburst): image generation and precise editing.
|
||||
- [Flare](https://developers.openai.com/api/docs/models/gpt-image-2.5-flare): fast, high-quality everyday image generation.
|
||||
- **4 real recreations**: [#532 lemon campaign](https://gpt-image2.canghe.ai/gpt-image-2-5/?lang=en&case=gallery-532-test), [#527 Rio diorama](https://gpt-image2.canghe.ai/gpt-image-2-5/?lang=en&case=gallery-527-test), [#523 Manhattan watercolor](https://gpt-image2.canghe.ai/gpt-image-2-5/?lang=en&case=gallery-523-test), and [#510 Bichon Shop icon](https://gpt-image2.canghe.ai/gpt-image-2-5/?lang=en&case=gallery-510-test). Each preserves its original gallery image and uses the full gallery prompt for one new built-in image generation, without a reference image. A case selector opens any example directly. [Images, prompts and generation records](docs/design/gpt-image-2-5/real-cases.md). Original generation conditions and exact tool model IDs remain unverified; demonstration examples are labeled separately.
|
||||
|
||||
The spotlight runs independently. Existing GPT-Image2 cases, templates, Skill, and generation tools remain available. This update does not add live 2.5 image generation.
|
||||
|
||||
<p align="center">
|
||||
<a href="https://gpt-image2.canghe.ai/gpt-image-2-5/?lang=en">
|
||||
<img src="docs/design/gpt-image-2-5/case532-preview.jpg" alt="GPT Image 2.5 spotlight preview — case 532 recreation" width="900">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
## 🌐 Visual Website
|
||||
|
||||
Use the live site at [gpt-image2.canghe.ai](https://gpt-image2.canghe.ai/) to browse the gallery as a product experience: open large previews, copy full prompts, filter by style or scenario, test generation after Google sign-in, and jump back to the source case on GitHub.
|
||||
|
||||
@@ -20,6 +20,22 @@
|
||||
<a href="./README.md">English</a> | <strong>简体中文</strong> | <a href="./README.ja.md">日本語</a>
|
||||
</p>
|
||||
|
||||
## GPT Image 2.5 专区
|
||||
|
||||
[进入 2.5 专区](https://gpt-image2.canghe.ai/gpt-image-2-5/):先了解 Sunburst 与 Flare,再通过共享 Prompt、滑动 / 并排对照、原图放大和参数说明体验新旧模型的对比方式。
|
||||
|
||||
- [Sunburst](https://developers.openai.com/api/docs/models/gpt-image-2.5-sunburst):面向精细图片生成与编辑。
|
||||
- [Flare](https://developers.openai.com/api/docs/models/gpt-image-2.5-flare):面向快速、高质量的日常图片生成。
|
||||
- **已加入 4 组真实案例复现**:[532 柠檬广告](https://gpt-image2.canghe.ai/gpt-image-2-5/?case=gallery-532-test)、[527 里约纸雕](https://gpt-image2.canghe.ai/gpt-image-2-5/?case=gallery-527-test)、[523 曼哈顿水彩](https://gpt-image2.canghe.ai/gpt-image-2-5/?case=gallery-523-test)、[510 Bichon Shop 图标](https://gpt-image2.canghe.ai/gpt-image-2-5/?case=gallery-510-test)。每组保留图库原图,复用站内完整提示词,通过内置生图生成一次新结果,不输入参考图;可用案例下拉框直接切换。[查看图片、提示词与生成记录](docs/design/gpt-image-2-5/real-cases.md)。原图生成条件与工具具体模型 ID 未核验,其他示意案例继续单独标注。
|
||||
|
||||
专区独立运行;原有 GPT-Image2 案例、模板、Skill 和在线生成入口继续保留。本次更新未接入 2.5 在线生图。
|
||||
|
||||
<p align="center">
|
||||
<a href="https://gpt-image2.canghe.ai/gpt-image-2-5/">
|
||||
<img src="docs/design/gpt-image-2-5/case532-preview.jpg" alt="GPT Image 2.5 专区预览:案例 532 真实复现" width="900">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
## 🌐 可视化网站
|
||||
|
||||
访问 [gpt-image2.canghe.ai](https://gpt-image2.canghe.ai/) 可以用产品化方式浏览案例:查看大图、复制完整 Prompt、按风格或场景筛选、配置个人 APIMart Key 或登录后测试生成,并快速跳回 GitHub 源案例。
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
# GPT Image 2.5 spotlight — design QA
|
||||
|
||||
final result: passed
|
||||
|
||||
Reviewed on 2026-09-09. This pass covers the isolated spotlight and its navigation entry in the existing gallery. It does not certify model quality or a public deployment.
|
||||
|
||||
## Publication preparation
|
||||
|
||||
The scoped change was reapplied to the latest remote main commit `b477278` in an isolated worktree. It retains the remote branch's 541 gallery records, local API plugin, dependencies, payment endpoints and community routes. Existing README text is unchanged outside the new spotlight sections. All four prompt, original-image and output-image hashes match their saved generation records.
|
||||
|
||||
The clean installation and production build pass. `npm test` passes 40 tests and `npm run test:apimart` passes 24 tests, with no failures. Browser checks against that build confirm seven case options, both distinct Rio images loading and the original #527 detail modal opening correctly. The original working directory remains separate from the publication branch.
|
||||
|
||||
## Follow-up: keep both images visible in narrow windows
|
||||
|
||||
The user reported seeing only one image. In the actual 491 × 734 in-app browser, both Rio assets had loaded, but the under-600-pixel layout stacked them vertically. The second image began at y=1010, below the initial viewport. The side-by-side canvas now retains two columns at narrow widths and uses a 12:7 frame with contained images. Compact labels remain left GPT 2.0 and right GPT 2.5. The enlargement dialog still offers larger individual images for inspection.
|
||||
|
||||
Verified in the production preview: both images share the same top edge and fit within the viewport at 491 × 734 and 390 × 844, with no horizontal overflow. The 1686-pixel Chrome layout retains its original geometry. Mobile enlargement opens and closes, and the left detail link opens the original #527 modal. Browser Back returns to the comparison; the console reports no errors or warnings. Build and whitespace checks passed. Temporary viewport sizing was reset, and the user's open previews were refreshed. Inspected evidence: [actual narrow window](docs/design/gpt-image-2-5/narrow-pair-491.jpg) and [390-pixel mobile](docs/design/gpt-image-2-5/narrow-pair-390.jpg). This supersedes the earlier stacked mobile canvas screenshots below. No P0/P1/P2 issue remains.
|
||||
|
||||
## Follow-up: three more real comparisons
|
||||
|
||||
The spotlight now has four real recreations followed by three labeled demonstrations. Added #527 Rio travel diorama, #523 Manhattan watercolor and #510 Bichon Shop icon, each generated once from the unchanged gallery prompt without a reference image or post-generation editing. The [case index](docs/design/gpt-image-2-5/real-cases.md) links the workspace PNGs, complete prompts and generation records. Input hashes, source/output hashes and actual dimensions were verified against all three new records.
|
||||
|
||||
A localized case selector above the next button opens any of the seven examples directly. Both selection methods reset the split to 50%, default real cases to side-by-side and update the case URL. The left GPT 2.0 image links to its existing gallery detail modal; the right GPT 2.5 image displays the new output. All three README spotlight sections now list the four real cases and share the updated [homepage screenshot](docs/design/gpt-image-2-5/case532-preview.jpg).
|
||||
|
||||
Inspected evidence: [Rio](docs/design/gpt-image-2-5/case527-preview.jpg), [Manhattan](docs/design/gpt-image-2-5/case523-preview.jpg), [Bichon Shop](docs/design/gpt-image-2-5/case510-preview.jpg), and [mobile](docs/design/gpt-image-2-5/more-cases-mobile.jpg). Desktop captures are 1386 × 1283 pixels at a 1386 × 1135 CSS viewport; mobile is a 390 × 2151 full-page capture at 390 × 844. Images fit their panels, the selector remains within the sidebar, and the selected navy/cyan/lime design is retained. No P0/P1/P2 issue remains.
|
||||
|
||||
Production browser verification passed for all new image pairs, exact prompts, labels, source details and case URLs. Each detail link opens the matching original gallery modal; Back returns to the spotlight. English selection and case URLs survive reload, the last demo wraps to the first real case, and the mobile generation-record dialog opens and closes with Escape. There is no horizontal overflow at 390 or 1386 pixels, and the console reports no errors or warnings. `npm run build` and `git diff --check` passed. The original gallery code and case data are unchanged from this follow-up's baseline; original generation code, gallery styles and configuration retain their earlier baseline contents. No commit, push or public deployment was performed.
|
||||
|
||||
## Follow-up: version labels and original-case details
|
||||
|
||||
The project owner requested explicit display labels: left **GPT 2.0**, right **GPT 2.5**. These appear in the comparison and enlarged views. Tool-reported model metadata is retained separately in the generation record.
|
||||
|
||||
The left image now has **查看详情 / View details**, linked to the corresponding gallery URL (`/?case=532` for the real test). The original gallery reads a valid numeric case parameter after loading its case data and opens its existing detail modal. Closing the modal removes the case parameter, so an ordinary reload does not reopen it. Existing demo cases #531 and #526 link to their own original details; the illustrative mug has no fabricated source link.
|
||||
|
||||
Browser verification passed on the production preview: labels are correct; side-by-side, slider and 390-pixel mobile clicks open the original #532 modal with `/images/case532.jpg` and the matching title; closing clears the parameter; the regular gallery reload has no modal; browser Back returns to the spotlight; the browser console reports no errors or warnings. `npm run build` and `git diff --check` passed. The current [desktop preview](docs/design/gpt-image-2-5/case532-preview.jpg) and [mobile preview](docs/design/gpt-image-2-5/case532-mobile.jpg) include the new labels and detail action. No P0/P1/P2 issue remains.
|
||||
|
||||
## Follow-up: first real case recreation
|
||||
|
||||
The user requested a real website case generated with the built-in image tool. Case #532 was generated once from the exact 8143-character gallery prompt, with no reference image and no post-generation edits. The source, unchanged prompt, output dimensions, timing and SHA-256 hashes are recorded in [case532-test-record.json](docs/design/gpt-image-2-5/case532-test-record.json); the complete input is in [case532-test-input.json](docs/design/gpt-image-2-5/case532-test-input.json).
|
||||
|
||||
The real case is now the first example and defaults to side-by-side comparison. Its record panel replaces model-selection radios because the tool returned no specific model ID, quality setting or cost. The original gallery image and new generated image are distinct. The other three examples retain their demonstration labels and controls. This is a single recreation using the site's documented prompt; the original generation conditions were not independently verified.
|
||||
|
||||
Current evidence: [desktop](docs/design/gpt-image-2-5/case532-preview.jpg), [mobile](docs/design/gpt-image-2-5/case532-mobile.jpg), [selected design and current page together](docs/design/gpt-image-2-5/case532-design-comparison.jpg), and [previous controls and current record panel together](docs/design/gpt-image-2-5/case532-controls-comparison.jpg). Desktop viewport is 1386 × 1135 CSS pixels; the capture is 1386 × 1283 pixels, cropped to the top 1135 pixels for the full-view comparison. Mobile viewport is 390 × 844 with a 390 × 2396 full-page capture. Both are 1 image pixel per CSS pixel.
|
||||
|
||||
The current evidence was inspected. The six-panel images, source attribution and generated observations are intentional content changes requested by the user. Fonts, navy/cyan tokens, hero, column alignment and button hierarchy retain design 1. Portrait images are fully contained on desktop and shown at their native aspect ratios in the mobile stacked view. No P0/P1/P2 layout or interaction issue remains. Existing P3 font and asset differences below still apply.
|
||||
|
||||
Verified: two different images load at their recorded dimensions; the real case has no model radios; returning to a demonstration restores its two radios and shared image; slider keyboard adjustment works; generation-record and image dialogs open and close; English labels and default side-by-side state survive reload; neither desktop nor mobile overflows; the production session reports zero console errors or warnings. The exact prompt matches the gallery source, test input and rendered-case data. `npm run build` passes, and the original gallery bundle is unchanged. README sections in all three languages now describe the first real recreation and use its new screenshot.
|
||||
|
||||
The new output retains the grid and readable LIMORA branding. Panel 2 uses a dripping lemon half instead of the requested floating slice; extra text appears on the cart and campaign strip. These are observations about the single output, without a model ranking claim. The previous demonstration-only delivery boundary is superseded by this section. No public deployment or repository push was performed.
|
||||
|
||||
## Reference and evidence
|
||||
|
||||
- Selected visual truth: design 1, the first displayed immersive slider design, preserved as [design-1.jpg](docs/design/gpt-image-2-5/design-1.jpg).
|
||||
- Portable reference: [design-1.jpg](docs/design/gpt-image-2-5/design-1.jpg).
|
||||
- Verified production build preview: `http://127.0.0.1:4179/gpt-image-2-5/`.
|
||||
- Final browser screenshot: [preview.jpg](docs/design/gpt-image-2-5/preview.jpg).
|
||||
- Full-view comparison, reference left and implementation right: [comparison.jpg](docs/design/gpt-image-2-5/comparison.jpg).
|
||||
- Focused comparisons: [hero typography and artwork](docs/design/gpt-image-2-5/hero-comparison.jpg), [prompt and controls](docs/design/gpt-image-2-5/controls-comparison.jpg).
|
||||
- Responsive evidence: [mobile](docs/design/gpt-image-2-5/mobile.jpg), [mobile image dialog](docs/design/gpt-image-2-5/mobile-dialog.jpg), [English example](docs/design/gpt-image-2-5/english.jpg).
|
||||
|
||||
Desktop state: Chinese, ceramic mug, Sunburst selected, slider at 50%, dialogs closed. Source size is 1386 × 1135 pixels. The implementation CSS viewport is 1386 × 1135; the clear full-page capture is 1386 × 1287 pixels. The combined comparison uses the implementation's top 1135 pixels without scaling. Evidence is 1 image pixel per CSS pixel. Additional explanatory text and the footer are below the reference crop.
|
||||
|
||||
Mobile CSS viewport is 390 × 844, with a 390 × 1719 full-page capture. English evidence is 1386 × 1282 and uses the travel example. Those views validate responsiveness and content states; there is no supplied mobile or English reference for pixel comparison. A 1024-pixel intermediate viewport was checked for overflow. The temporary viewport override was reset after review.
|
||||
|
||||
## Findings and iteration history
|
||||
|
||||
No actionable P0, P1, or P2 findings remain.
|
||||
|
||||
1. **P2 — vertical spacing.** The [first comparison](docs/design/gpt-image-2-5/iteration-1.jpg) placed the workspace around y=475 instead of the reference's y=455 and made the sidebar taller. Reduced hero and sidebar spacing. The final workspace begins at y=455.48 and the sidebar aligns with the main comparison panel.
|
||||
2. **P2 — hero artwork treatment.** The first image had a rectangular background edge and its cyan rim sat too far right. Added a radial mask to the generated raster, increased its display size, and shifted the image left. The final full-view and hero crops show a blended dark sphere beside the copy.
|
||||
3. **P2 — mobile density and skip-link capture.** The square mobile canvas left excessive vertical space around the landscape image. Changed the mobile slider to 4:3 and stacked comparison to 2:3. Replaced the skip-link's offscreen transform with clipping so full-page capture also hides it when unfocused. The final mobile evidence has no floating skip-link overlay or horizontal overflow.
|
||||
4. **Development warning.** Editing imported case data could remount the root during hot reload. Separated the React entry from the exported App component. The production browser session reports no errors or warnings. This finding is separate from visual fidelity.
|
||||
|
||||
The revised implementation was recaptured and compared with the reference in the same image after the fixes. Focused control and hero crops were inspected alongside the full view.
|
||||
|
||||
## Required fidelity surfaces
|
||||
|
||||
| Surface | Assessment |
|
||||
| --- | --- |
|
||||
| Fonts and typography | Large bold display heading, smaller Chinese headline, muted descriptions, and compact controls preserve the reference hierarchy. The system sans-serif stack has modest glyph-width differences from the generated reference. Chinese and English remain readable without truncating controls. |
|
||||
| Spacing and layout rhythm | Wide image panel, narrow prompt sidebar, common top edge, border radii, and button grouping follow design 1. Mobile becomes one column; no horizontal overflow at 390, 1024, or 1386 pixels. |
|
||||
| Colors and tokens | Navy background, pale text, cyan selected states, and cyan-to-lime primary buttons match the source direction. Focus outlines remain visible. Native radio rendering varies slightly by browser. |
|
||||
| Image quality | Both custom assets are generated raster images. The mug preserves warm product photography, a right-facing handle, wood, books, and blurred foliage. The sphere has no visible rectangular edge. Portrait examples use containment to retain their full artwork. |
|
||||
| Copy and content | Official model names and document links replace speculative descriptions. Both comparison panels explicitly use illustrative material. No latency, price, or model-performance claims are fabricated. Shared prompts, source links, model selection, and parameters are presented in Chinese and English. |
|
||||
|
||||
Expected adaptations: existing project branding is retained; the reference's login action becomes a return-to-gallery link; model radios select the planned comparison model; an example counter, source attribution, methodology, and explicit demonstration notice are added. The original generation and account flows remain in the gallery.
|
||||
|
||||
P3 follow-up only: the generated mug silhouette, Chinese glyph widths, decorative lettering, and native radio appearance vary slightly from the reference. These do not block use or change the selected layout.
|
||||
|
||||
## Interaction and regression checks
|
||||
|
||||
- Slider supports pointer changes and keyboard arrow changes; tested 50% → 51% → 50%.
|
||||
- Side-by-side mode works; mobile stacks the two images.
|
||||
- Sunburst and Flare selection updates the visible label and the official model document in the parameters dialog.
|
||||
- Copy prompt shows success; pasting through the browser UI into the gallery search reproduced the exact prompt.
|
||||
- Three examples cycle and wrap. Case query parameters survive reload; English selection survives reload through `lang=en`.
|
||||
- Image enlargement and parameters dialogs open and close; Escape works, images load, and closing restores body scrolling. Dialogs have accessible names.
|
||||
- Original gallery search for `531` returns one match; its original case-details modal opens and closes. The new navigation entry opens the isolated spotlight.
|
||||
- Production preview returns HTTP 200 for the homepage, spotlight, spotlight with query parameters, and both reused gallery images. Main images load in the browser; the fresh production session has zero console errors or warnings.
|
||||
- `npm run build` passes and emits both HTML entries with separate gallery and spotlight CSS/JS bundles. `git diff --check` passes.
|
||||
- Starting-worktree comparison confirms the original gallery change is one navigation link. Existing gallery CSS, model adapter, generation endpoint, package files, Vercel configuration, and case data are unchanged from the starting worktree. All pre-existing README content is retained outside the added spotlight blocks.
|
||||
- English, Chinese, and Japanese README blocks include the spotlight link, official documentation, truthful demonstration status, and the final preview image.
|
||||
|
||||
## Initial delivery boundary (before the real-case follow-up)
|
||||
|
||||
The page and README changes are complete locally. Actual GPT Image 2 versus GPT Image 2.5 generated outputs, measured settings/costs, and live 2.5 generation are outside this demonstration build. No commit, push, or public deployment was performed. The production preview is kept running and open for review.
|
||||
|
After Width: | Height: | Size: 181 KiB |
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"caseId": 510,
|
||||
"title": "Bichon Shop 拟物 App 图标",
|
||||
"source": "https://x.com/iamaiistudio/status/2071923809788285125",
|
||||
"prompt": "A macOS app icon for an app named 'Bichon Shop'. A single squircle icon with smooth continuous rounded corners, centered on a white canvas with padding, occupying about 80% of the canvas. Modern light skeuomorphic macOS App Store style. Only one icon.",
|
||||
"referenceImages": [],
|
||||
"tool": "image_gen.imagegen",
|
||||
"requestedModel": "built-in current model",
|
||||
"promptModified": false
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"caseId": 510,
|
||||
"date": "2026-09-09",
|
||||
"source": "https://x.com/iamaiistudio/status/2071923809788285125",
|
||||
"sourceImage": "data/images/case510.jpg",
|
||||
"sourceGenerationParametersVerified": false,
|
||||
"inputPromptPath": "docs/design/gpt-image-2-5/case510-test-input.json",
|
||||
"promptModified": false,
|
||||
"referenceImages": [],
|
||||
"sampleCount": 1,
|
||||
"tool": "image_gen.imagegen",
|
||||
"userStatedModel": "GPT Image 2.5",
|
||||
"toolReportedModel": null,
|
||||
"toolReportedQuality": null,
|
||||
"toolReportedCost": null,
|
||||
"startedAt": "2026-09-09T02:04:06.606Z",
|
||||
"finishedAt": "2026-09-09T02:06:42.762Z",
|
||||
"approximateCallWallClockSeconds": 156,
|
||||
"durationNote": "Wall-clock wait includes orchestration, queueing and transfer; not an isolated inference benchmark.",
|
||||
"outputImage": "src/assets/image25-case510-run1.png",
|
||||
"editedAfterGeneration": false,
|
||||
"observations": [
|
||||
"One rounded-square icon is centered on a white canvas with padding.",
|
||||
"The dog has detailed curls, and the bag has rope handles and visible paper texture.",
|
||||
"The background changes from pink to cream, with different Bichon Shop lettering."
|
||||
],
|
||||
"interpretation": "One new generation compared with an existing gallery image using its documented prompt. Original generation settings and tool-reported model ID are unverified.",
|
||||
"displayLabels": {
|
||||
"left": "GPT 2.0",
|
||||
"right": "GPT 2.5",
|
||||
"basis": "Project owner requested these display labels. Tool-reported metadata remains separate."
|
||||
},
|
||||
"sourceDimensions": {
|
||||
"width": 1254,
|
||||
"height": 1254
|
||||
},
|
||||
"outputDimensions": {
|
||||
"width": 1254,
|
||||
"height": 1254
|
||||
},
|
||||
"promptSha256": "6427e7f61957e58d42fbcca7bca757d65c99489587f471ce4bfe8f402f1008de",
|
||||
"sourceImageSha256": "f2422d47e1ecc53ce285088b36b574c8c082784759a07ec3fb3e8da0545be3ec",
|
||||
"outputSha256": "5fd4ed3164787dfc42c8de6088d3ab9b6e9cb9c04a164d0bae95ec04d10f5040"
|
||||
}
|
||||
|
After Width: | Height: | Size: 311 KiB |
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"caseId": 523,
|
||||
"title": "曼哈顿公园水彩旅行插画",
|
||||
"source": "https://x.com/Taaruk_/status/2090307485374578755",
|
||||
"prompt": "Create a vertical editorial travel illustration inspired by vintage European travel posters, featuring a peaceful summer afternoon in a grand city park with a recognizable Manhattan-style skyline in the background. Use delicate hand-drawn ink outlines combined with soft, slightly imperfect watercolor washes on warm textured cream paper. Show a wide green lawn filled with people relaxing, reading, walking, jogging, cycling, and having picnics. In the foreground, a casually dressed young couple sits together on a picnic blanket beside a woven basket. Include elegant black vintage park lamps, winding pathways, dense leafy trees framing the composition, and detailed historic and modern skyscrapers rising behind the park. Add a small picturesque stone arch bridge over a calm pond near the bottom of the artwork. Use muted sage green, olive, warm beige, soft blue, pale gray, and subtle golden sunlight, with natural watercolor bleeding, paper grain, fine pen hatching, and an airy sophisticated travel-journal aesthetic. No text, no letters, no logos, no typography, no captions, no signs. Vertical 4:5 composition, highly detailed, elegant, nostalgic, handcrafted watercolor-and-ink illustration.",
|
||||
"referenceImages": [],
|
||||
"tool": "image_gen.imagegen",
|
||||
"requestedModel": "built-in current model",
|
||||
"promptModified": false
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"caseId": 523,
|
||||
"date": "2026-09-09",
|
||||
"source": "https://x.com/Taaruk_/status/2090307485374578755",
|
||||
"sourceImage": "data/images/case523.jpg",
|
||||
"sourceGenerationParametersVerified": false,
|
||||
"inputPromptPath": "docs/design/gpt-image-2-5/case523-test-input.json",
|
||||
"promptModified": false,
|
||||
"referenceImages": [],
|
||||
"sampleCount": 1,
|
||||
"tool": "image_gen.imagegen",
|
||||
"userStatedModel": "GPT Image 2.5",
|
||||
"toolReportedModel": null,
|
||||
"toolReportedQuality": null,
|
||||
"toolReportedCost": null,
|
||||
"startedAt": "2026-09-09T02:04:06.606Z",
|
||||
"finishedAt": "2026-09-09T02:05:07.234Z",
|
||||
"approximateCallWallClockSeconds": 61,
|
||||
"durationNote": "Wall-clock wait includes orchestration, queueing and transfer; not an isolated inference benchmark.",
|
||||
"outputImage": "src/assets/image25-case523-run1.png",
|
||||
"editedAfterGeneration": false,
|
||||
"observations": [
|
||||
"The stone bridge and pond are larger and more prominent in the foreground.",
|
||||
"Trees fill more of the composition; watercolor-and-ink styling is retained.",
|
||||
"No visible text was added."
|
||||
],
|
||||
"interpretation": "One new generation compared with an existing gallery image using its documented prompt. Original generation settings and tool-reported model ID are unverified.",
|
||||
"displayLabels": {
|
||||
"left": "GPT 2.0",
|
||||
"right": "GPT 2.5",
|
||||
"basis": "Project owner requested these display labels. Tool-reported metadata remains separate."
|
||||
},
|
||||
"sourceDimensions": {
|
||||
"width": 1085,
|
||||
"height": 1449
|
||||
},
|
||||
"outputDimensions": {
|
||||
"width": 1122,
|
||||
"height": 1402
|
||||
},
|
||||
"promptSha256": "2459c90b2604b453a6e7036f64a43400c5cd7930653cb11b9df953327ae94dc8",
|
||||
"sourceImageSha256": "8aae8ada81d5518d972a910ce3b6efbfd063d0f794d071b8fb9d63ecd5047441",
|
||||
"outputSha256": "e6b8a068836b2ab3b027567ad3d376228856de96920f5cf45de732534c75280f"
|
||||
}
|
||||
|
After Width: | Height: | Size: 274 KiB |
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"caseId": 527,
|
||||
"title": "Rio 旅行票据纸雕立体海报",
|
||||
"source": "https://x.com/john_my07/status/2091408386466214031",
|
||||
"prompt": "Create a highly detailed, photorealistic miniature travel-poster diorama inspired by Rio de Janeiro, arranged as a handcrafted 3D paper scene on a warm ivory, slightly textured background.\n\nIn the foreground, a realistic human hand holds a vintage Brazilian travel ticket or Rio-themed transit card vertically on the left side. Give the card aged paper texture, subtle printing imperfections, elegant typography, and authentic-looking travel details. From behind the card, a miniature Rio de Janeiro landscape physically rises outward like an intricate pop-up diorama.\n\nMake Christ the Redeemer the dominant central landmark, positioned high above a miniature cityscape with lush green mountains surrounding it. Below, build a tiny realistic Rio street featuring a classic yellow taxi, colorful buildings, palm trees, pedestrians, cyclists, street lamps, tiled sidewalks, and small Brazilian urban details. Add Copacabana beach elements in the distance with tiny umbrellas, beachgoers, and a glimpse of the Atlantic Ocean. Layer the architecture and terrain so everything appears physically constructed from paper, wood, plaster, and miniature materials, with convincing depth, cast shadows, overlapping surfaces, and a slight three-quarter perspective.\n\nAround the main 3D scene, incorporate delicate black, charcoal, and muted sepia hand-drawn travel illustrations on the cream paper. Include a small Sugarloaf Mountain sketch in the upper left, an artistic Copacabana promenade illustration in the upper right, a detailed Selarón Steps sketch along the right side, and a small Ipanema beachfront skyline drawing near the bottom. Add subtle handwritten travel notes, tiny map markings, architectural outlines, compass symbols, postage-stamp details, and understated Brazilian travel annotations.\n\nKeep the composition refined rather than crowded. Blend realistic miniature photography with vintage travel-journal design, tactile paper fibers, faint ink bleed, imperfect hand-drawn lines, warm natural studio lighting, gentle shadows, subtle film grain, and a sophisticated cream, charcoal, muted green, ocean blue, and Brazilian yellow palette.\n\nThe final image should feel like a premium collectible Rio de Janeiro travel postcard transformed into a physical miniature world, with the central diorama sharply detailed and the surrounding illustrations slightly softer. Highly realistic human hand and fingers, believable miniature materials, cinematic product photography, editorial travel-magazine aesthetic, shallow depth of field, ultra-fine textures, photorealistic 3D details, vertical 4:5 composition, 8K quality.",
|
||||
"referenceImages": [],
|
||||
"tool": "image_gen.imagegen",
|
||||
"requestedModel": "built-in current model",
|
||||
"promptModified": false
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
{
|
||||
"caseId": 527,
|
||||
"date": "2026-09-09",
|
||||
"source": "https://x.com/john_my07/status/2091408386466214031",
|
||||
"sourceImage": "data/images/case527.jpg",
|
||||
"sourceGenerationParametersVerified": false,
|
||||
"inputPromptPath": "docs/design/gpt-image-2-5/case527-test-input.json",
|
||||
"promptModified": false,
|
||||
"referenceImages": [],
|
||||
"sampleCount": 1,
|
||||
"tool": "image_gen.imagegen",
|
||||
"userStatedModel": "GPT Image 2.5",
|
||||
"toolReportedModel": null,
|
||||
"toolReportedQuality": null,
|
||||
"toolReportedCost": null,
|
||||
"startedAt": "2026-09-09T02:04:06.606Z",
|
||||
"finishedAt": "2026-09-09T02:06:13.172Z",
|
||||
"approximateCallWallClockSeconds": 127,
|
||||
"durationNote": "Wall-clock wait includes orchestration, queueing and transfer; not an isolated inference benchmark.",
|
||||
"outputImage": "src/assets/image25-case527-run1.png",
|
||||
"editedAfterGeneration": false,
|
||||
"observations": [
|
||||
"The ticket, Christ the Redeemer, yellow taxi and miniature base are present.",
|
||||
"Building facades are more prominent and handwritten annotations are denser than in the gallery image.",
|
||||
"This is the first untouched output from the exact gallery prompt."
|
||||
],
|
||||
"interpretation": "One new generation compared with an existing gallery image using its documented prompt. Original generation settings and tool-reported model ID are unverified.",
|
||||
"displayLabels": {
|
||||
"left": "GPT 2.0",
|
||||
"right": "GPT 2.5",
|
||||
"basis": "Project owner requested these display labels. Tool-reported metadata remains separate."
|
||||
},
|
||||
"sourceDimensions": {
|
||||
"width": 1122,
|
||||
"height": 1402
|
||||
},
|
||||
"outputDimensions": {
|
||||
"width": 1122,
|
||||
"height": 1402
|
||||
},
|
||||
"promptSha256": "d37e97eedf944f43f6c429b7d0ee157a7470477cdc952d8d1337e8c7e4085feb",
|
||||
"sourceImageSha256": "fe22ae11fed9d5ff1fc20abefd80c137a560c1b21e3775f32c89c6a6a89be226",
|
||||
"outputSha256": "0d83a536f34893daeaa90150f18f7157c8165a36f12d305bf567e321be992627"
|
||||
}
|
||||
|
After Width: | Height: | Size: 93 KiB |
|
After Width: | Height: | Size: 607 KiB |
|
After Width: | Height: | Size: 222 KiB |
|
After Width: | Height: | Size: 258 KiB |
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"caseId": 532,
|
||||
"date": "2026-09-09",
|
||||
"source": "https://x.com/ou_zhen599/status/2091160215928574397",
|
||||
"sourceImage": "data/images/case532.jpg",
|
||||
"sourceDimensions": {
|
||||
"width": 3277,
|
||||
"height": 4096
|
||||
},
|
||||
"sourceGenerationParametersVerified": false,
|
||||
"inputPromptPath": "docs/design/gpt-image-2-5/case532-test-input.json",
|
||||
"promptModified": false,
|
||||
"referenceImages": [],
|
||||
"sampleCount": 1,
|
||||
"tool": "image_gen.imagegen",
|
||||
"userStatedModel": "GPT Image 2.5",
|
||||
"toolReportedModel": null,
|
||||
"toolReportedQuality": null,
|
||||
"toolReportedCost": null,
|
||||
"startedAt": "2026-09-09T01:44:03.991Z",
|
||||
"finishedAt": "2026-09-09T01:46:15.733Z",
|
||||
"approximateCallWallClockSeconds": 132,
|
||||
"durationNote": "Wall-clock wait includes orchestration, queueing and transfer; not an isolated inference benchmark.",
|
||||
"outputImage": "src/assets/image25-case532-run1.png",
|
||||
"outputDimensions": {
|
||||
"width": 1024,
|
||||
"height": 1536
|
||||
},
|
||||
"editedAfterGeneration": false,
|
||||
"observations": [
|
||||
"The requested 2-column by 3-row grid and recurring green dress are present.",
|
||||
"LIMORA is readable on the hero glass. Citrus, ice, juice and glass are visually detailed.",
|
||||
"Panel 2 shows a dripping lemon half instead of the requested floating lemon slice.",
|
||||
"Extra branding appears on the cart and the lower campaign strip."
|
||||
],
|
||||
"interpretation": "One new generation compared with an existing gallery image using its documented prompt. Original generation settings and actual model IDs are unverified, so this is not a controlled model benchmark.",
|
||||
"promptSha256": "fb302b56879b7f824d551b1f7b6d87135fffab5b34635b24301102c65ead3e17",
|
||||
"outputSha256": "e79583d6003f3b01e62166ae5cb95e2020ed348d5a924e7af9e321ae8d39dc80",
|
||||
"sourceImageSha256": "da0294912cd02ddc180aadb419095c9d72e06fd90f5f002c76869c461a9905c9",
|
||||
"displayLabels": {
|
||||
"left": "GPT 2.0",
|
||||
"right": "GPT 2.5",
|
||||
"basis": "Project owner requested these display labels. Original tool-reported model metadata remains unchanged."
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 524 KiB |
|
After Width: | Height: | Size: 97 KiB |
|
After Width: | Height: | Size: 252 KiB |
|
After Width: | Height: | Size: 230 KiB |
|
After Width: | Height: | Size: 259 KiB |
|
After Width: | Height: | Size: 173 KiB |
|
After Width: | Height: | Size: 501 KiB |
|
After Width: | Height: | Size: 113 KiB |
|
After Width: | Height: | Size: 112 KiB |
|
After Width: | Height: | Size: 118 KiB |
|
After Width: | Height: | Size: 107 KiB |
|
After Width: | Height: | Size: 131 KiB |
|
After Width: | Height: | Size: 230 KiB |
@@ -0,0 +1,18 @@
|
||||
# GPT 2.0 / GPT 2.5 案例对比记录
|
||||
|
||||
现有 4 组真实复现。左侧保留站内原图,右侧由 Codex 内置生图工具使用完整站内提示词生成;每组首次生成 1 张,无参考图,也未对结果进行后期修改。显示版本沿用项目负责人指定的 GPT 2.0 / GPT 2.5 标签,工具实际返回的信息单独记录。
|
||||
|
||||
| 案例 | 本次生成原图 | 完整提示词 | 生成记录 |
|
||||
| --- | --- | --- | --- |
|
||||
| [#532 六宫格柠檬饮料微缩广告](https://gpt-image2.canghe.ai/gpt-image-2-5/?case=gallery-532-test) | [PNG](../../../src/assets/image25-case532-run1.png) | [完整输入](case532-test-input.json) | [参数与来源](case532-test-record.json) |
|
||||
| [#527 Rio 旅行票据纸雕立体海报](https://gpt-image2.canghe.ai/gpt-image-2-5/?case=gallery-527-test) | [PNG](../../../src/assets/image25-case527-run1.png) | [完整输入](case527-test-input.json) | [参数与来源](case527-test-record.json) |
|
||||
| [#523 曼哈顿公园水彩旅行插画](https://gpt-image2.canghe.ai/gpt-image-2-5/?case=gallery-523-test) | [PNG](../../../src/assets/image25-case523-run1.png) | [完整输入](case523-test-input.json) | [参数与来源](case523-test-record.json) |
|
||||
| [#510 Bichon Shop 拟物 App 图标](https://gpt-image2.canghe.ai/gpt-image-2-5/?case=gallery-510-test) | [PNG](../../../src/assets/image25-case510-run1.png) | [完整输入](case510-test-input.json) | [参数与来源](case510-test-record.json) |
|
||||
|
||||
本次新增的观察:
|
||||
|
||||
- #527:票据、基督像、黄色出租车和纸质底座完整,街道立面更醒目,周边注记更密集。
|
||||
- #523:石桥与池塘变成更明显的前景,树木覆盖更满,保留水彩与钢笔风格和无字画面。
|
||||
- #510:单个圆角图标与白底留白保留,毛发、绳把和纸袋材质更细,底色与品牌字体变化明显。
|
||||
|
||||
这些是单次结果的视觉观察。原图生成条件未独立核验,工具未返回具体模型 ID、质量档位或费用。
|
||||
@@ -0,0 +1,20 @@
|
||||
<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta name="theme-color" content="#060914" />
|
||||
<title>GPT Image 2.5 专区 · 同提示词对比 | GPT-Image2 Gallery</title>
|
||||
<meta name="description" content="了解 GPT Image 2.5 Sunburst 与 Flare,体验同一提示词的滑动与并排对比。已收录站内真实案例的完整提示词复现与生成记录,其他示意内容单独标注。" />
|
||||
<link rel="canonical" href="https://gpt-image2.canghe.ai/gpt-image-2-5/" />
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:title" content="GPT Image 2.5 专区 · 同一提示词,从细节看变化" />
|
||||
<meta property="og:description" content="Sunburst / Flare 官方介绍、同 Prompt 对比交互与可复制提示词。浏览原案例与内置生图工具生成的真实复现结果。" />
|
||||
<meta property="og:url" content="https://gpt-image2.canghe.ai/gpt-image-2-5/" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<noscript>GPT Image 2.5 专区:Sunburst 面向精细生成与编辑,Flare 面向快速日常生成。请启用 JavaScript 体验对比,或<a href="/">返回原案例库</a>。</noscript>
|
||||
<script type="module" src="/src/image25/main.jsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
After Width: | Height: | Size: 1.5 MiB |
|
After Width: | Height: | Size: 3.4 MiB |
|
After Width: | Height: | Size: 2.9 MiB |
|
After Width: | Height: | Size: 2.6 MiB |
|
After Width: | Height: | Size: 1.7 MiB |
|
After Width: | Height: | Size: 960 KiB |
@@ -0,0 +1,194 @@
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { ArrowRight, ArrowUpRight, Check, ChevronDown, ChevronsLeftRight, Columns2, Copy, Expand, Info, Settings2, Sun, WandSparkles, X, Zap } from 'lucide-react';
|
||||
import { comparisonCases, modelDocs } from './cases';
|
||||
import hero from '../assets/image25-hero.png';
|
||||
|
||||
const text = {
|
||||
zh: {
|
||||
brand: 'GPT-Image2 画廊', cases: '案例', zone: '2.5 专区', templates: '模板', back: '返回画廊',
|
||||
headline: '同一提示词,从细节看变化。',
|
||||
sunburstIntro: 'Sunburst:精细生成与编辑,适合注重编辑准确性的创作场景。',
|
||||
flareIntro: 'Flare:快速日常生成,适合日常图片创作与灵感探索。',
|
||||
compare: '查看对比', official: '官方介绍', slogan: ['更生动的想象', '在此展开。'], subSlogan: ['同一个想法,', '看见更多可能。'],
|
||||
demoNotice: '界面示意 · 对比图片非实测', demo: '示意图',
|
||||
demoExplanation: '本组两侧共用同一张示意图,仅用于体验对比交互。',
|
||||
testNotice: '真实案例复现 · 站内完整 Prompt', original: '图库原图', generated: '本次生成',
|
||||
testExplanation: '复用站内完整提示词,未输入参考图;原图生成条件未知,此处仅展示单次复现。',
|
||||
thisRun: '本次生成记录', completed: '已完成 · 单次生成', testHelp: '独立构图,建议并排查看',
|
||||
shared: '共享 Prompt', copy: '复制 Prompt', copied: '已复制', copyFailed: '复制失败,请选中上方文字手动复制。',
|
||||
choose: '选择 2.5 型号', sunburst: '精细生成与编辑', flare: '快速日常生成', params: '查看生成参数',
|
||||
next: '下一组', chooseCase: '选择对比案例', sideBySide: '并排', slider: '滑动', sliderHelp: '构图接近时,适合滑动对照',
|
||||
sliderLabel: '调整对比图片分界位置', enlarge: '放大查看', close: '关闭', viewDetails: '查看详情',
|
||||
source: '图片来源', focus: '观察重点', status: '对比状态', pending: '待实测',
|
||||
model: '计划对比型号', settings: '尺寸、质量、耗时与成本', notRecorded: '实测完成后公开',
|
||||
methodology: '实测将使用完全相同的 Prompt 与输入素材,分别记录模型、尺寸、质量设置和多次生成结果。相同质量名称可能对应不同计算量,请结合实际成本阅读。',
|
||||
modelDetails: '查看所选型号官方文档', promptLabel: '本组完整提示词',
|
||||
footer: 'GPT Image 2.5 专区', footerNote: '官方信息与实测结果分别标注,原案例库持续保留。',
|
||||
docsDate: '官方文档核对:2026-09-09', sample: '示意素材', skip: '跳到图片对比'
|
||||
},
|
||||
en: {
|
||||
brand: 'GPT-Image2 Gallery', cases: 'Cases', zone: 'Image 2.5', templates: 'Templates', back: 'Back to gallery',
|
||||
headline: 'Same prompt. See the details.',
|
||||
sunburstIntro: 'Sunburst: image generation and editing for workflows where editing precision matters most.',
|
||||
flareIntro: 'Flare: fast, high-quality everyday image generation and creative exploration.',
|
||||
compare: 'Explore comparison', official: 'Official guide', slogan: ['More vivid ideas', 'start here.'], subSlogan: ['One shared idea.', 'More possibilities.'],
|
||||
demoNotice: 'Interface demo · Images are not benchmark results', demo: 'Illustration',
|
||||
demoExplanation: 'This example uses the same illustration in both panels to demonstrate the controls.',
|
||||
testNotice: 'Real case recreation · Full gallery prompt', original: 'Gallery original', generated: 'New generation',
|
||||
testExplanation: 'The full gallery prompt was reused without a reference image. Original generation conditions are unknown; this is one recreation.',
|
||||
thisRun: 'Generation record', completed: 'Completed · One generation', testHelp: 'Different compositions: try side by side',
|
||||
shared: 'Shared prompt', copy: 'Copy prompt', copied: 'Copied', copyFailed: 'Copy failed. Select the prompt above and copy it manually.',
|
||||
choose: 'Choose a 2.5 model', sunburst: 'Precise generation & editing', flare: 'Fast everyday generation', params: 'View generation settings',
|
||||
next: 'Next example', chooseCase: 'Choose a comparison case', sideBySide: 'Side by side', slider: 'Slider', sliderHelp: 'Best for images with similar compositions',
|
||||
sliderLabel: 'Adjust image comparison divider', enlarge: 'Enlarge images', close: 'Close', viewDetails: 'View details',
|
||||
source: 'Image source', focus: 'Look closely at', status: 'Comparison status', pending: 'Awaiting real tests',
|
||||
model: 'Planned model comparison', settings: 'Size, quality, latency & cost', notRecorded: 'Published with the real tests',
|
||||
methodology: 'Tests will use the exact same prompt and input images, with model, size, quality, and repeated outputs recorded. The same quality name can use different compute; compare actual costs too.',
|
||||
modelDetails: 'Read the selected model documentation', promptLabel: 'Complete shared prompt',
|
||||
footer: 'GPT Image 2.5', footerNote: 'Official information and test results are labeled separately. The existing gallery remains available.',
|
||||
docsDate: 'Official docs checked: 2026-09-09', sample: 'Illustration', skip: 'Skip to comparison'
|
||||
}
|
||||
};
|
||||
|
||||
function initialState() {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
return { language: params.get('lang') === 'en' ? 'en' : 'zh', caseIndex: Math.max(0, comparisonCases.findIndex(item => item.id === params.get('case'))) };
|
||||
}
|
||||
|
||||
export default function App() {
|
||||
const [initial] = useState(initialState);
|
||||
const [language, setLanguage] = useState(initial.language);
|
||||
const [caseIndex, setCaseIndex] = useState(initial.caseIndex);
|
||||
const [model, setModel] = useState('sunburst');
|
||||
const [view, setView] = useState(comparisonCases[initial.caseIndex].result ? 'side' : 'slider');
|
||||
const [position, setPosition] = useState(50);
|
||||
const [copyState, setCopyState] = useState('');
|
||||
const [modal, setModal] = useState(null);
|
||||
const dialogRef = useRef(null);
|
||||
const copyTimer = useRef(null);
|
||||
const t = text[language];
|
||||
const item = comparisonCases[caseIndex];
|
||||
const modelName = model === 'sunburst' ? 'Sunburst' : 'Flare';
|
||||
const result = item.result;
|
||||
const notice = result ? t.testNotice : t.demoNotice;
|
||||
const explanation = result ? t.testExplanation : t.demoExplanation;
|
||||
const beforeLabel = 'GPT 2.0';
|
||||
const afterLabel = result ? result.label[language] : `GPT 2.5 · ${modelName}`;
|
||||
const sourceCaseId = result?.caseId || item.sourceCaseId;
|
||||
|
||||
useEffect(() => {
|
||||
document.documentElement.lang = language === 'zh' ? 'zh-CN' : 'en';
|
||||
document.title = language === 'zh' ? 'GPT Image 2.5 专区 · 同提示词对比 | GPT-Image2 Gallery' : 'GPT Image 2.5 · Same-prompt comparison | GPT-Image2 Gallery';
|
||||
const url = new URL(window.location.href);
|
||||
if (language === 'en') url.searchParams.set('lang', 'en'); else url.searchParams.delete('lang');
|
||||
if (caseIndex) url.searchParams.set('case', item.id); else url.searchParams.delete('case');
|
||||
window.history.replaceState({}, '', `${url.pathname}${url.search}${url.hash}`);
|
||||
}, [language, caseIndex, item.id]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!modal) return undefined;
|
||||
const dialog = dialogRef.current;
|
||||
const overflow = document.body.style.overflow;
|
||||
dialog.showModal();
|
||||
document.body.style.overflow = 'hidden';
|
||||
return () => { dialog.close(); document.body.style.overflow = overflow; };
|
||||
}, [modal]);
|
||||
|
||||
useEffect(() => () => clearTimeout(copyTimer.current), []);
|
||||
|
||||
async function copyPrompt() {
|
||||
clearTimeout(copyTimer.current);
|
||||
try { await navigator.clipboard.writeText(item.prompt); setCopyState('copied'); }
|
||||
catch { setCopyState('failed'); }
|
||||
copyTimer.current = setTimeout(() => setCopyState(''), 2500);
|
||||
}
|
||||
|
||||
function selectCase(nextIndex) {
|
||||
if (nextIndex < 0 || nextIndex >= comparisonCases.length) return;
|
||||
setCaseIndex(nextIndex);
|
||||
setView(comparisonCases[nextIndex].result ? 'side' : 'slider');
|
||||
setPosition(50);
|
||||
setCopyState('');
|
||||
clearTimeout(copyTimer.current);
|
||||
}
|
||||
|
||||
function nextCase() {
|
||||
selectCase((caseIndex + 1) % comparisonCases.length);
|
||||
}
|
||||
|
||||
function picture(label, side) {
|
||||
const generated = result && side === 'after';
|
||||
return <figure className={`image25-picture image25-picture-${side}`}>
|
||||
<img src={generated ? result.image : item.image} alt={generated ? result.alt[language] : item.alt[language]} draggable="false" />
|
||||
<figcaption className="image25-model-label">{label}</figcaption>
|
||||
{side === 'before' && sourceCaseId ? <a className="image25-demo-label image25-detail-link" href={`/?case=${sourceCaseId}`}>{t.viewDetails}<ArrowUpRight size={14} /></a> : <span className="image25-demo-label">{result ? (generated ? t.generated : t.original) : t.demo}</span>}
|
||||
</figure>;
|
||||
}
|
||||
|
||||
return <div className="image25-page">
|
||||
<a className="image25-skip" href="#comparison">{t.skip}</a>
|
||||
<header className="image25-header">
|
||||
<a className="image25-brand" href="/"><WandSparkles size={23} />{t.brand}</a>
|
||||
<nav aria-label={language === 'zh' ? '主导航' : 'Main navigation'}>
|
||||
<a href="/#gallery">{t.cases}</a>
|
||||
<a href="/gpt-image-2-5/" aria-current="page">{t.zone}</a>
|
||||
<a href="/#templates">{t.templates}</a>
|
||||
<a href="https://github.com/freestylefly/awesome-gpt-image-2" target="_blank" rel="noreferrer">GitHub</a>
|
||||
</nav>
|
||||
<div className="image25-header-actions">
|
||||
<label className="image25-language"><span className="image25-sr-only">Language / 语言</span><select value={language} onChange={event => setLanguage(event.target.value)}><option value="zh">中文</option><option value="en">EN</option></select><ChevronDown size={14} /></label>
|
||||
<a className="image25-button image25-back" href="/">{t.back}<ArrowRight size={18} /></a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<section className="image25-hero" aria-labelledby="image25-title">
|
||||
<div className="image25-hero-copy">
|
||||
<h1 id="image25-title">GPT Image 2.5</h1>
|
||||
<h2>{t.headline}</h2>
|
||||
<div className="image25-intro"><p>{t.sunburstIntro}</p><p>{t.flareIntro}</p></div>
|
||||
<div className="image25-hero-actions"><a className="image25-button" href="#comparison">{t.compare}<ArrowRight size={20} /></a><a className="image25-doc-link" href={modelDocs.guide} target="_blank" rel="noreferrer">{t.official}<ArrowUpRight size={17} /></a></div>
|
||||
</div>
|
||||
<div className="image25-hero-art" aria-hidden="true"><img src={hero} alt="" /><div><p>{t.slogan[0]}<br />{t.slogan[1]}</p><span>{t.subSlogan[0]}<br />{t.subSlogan[1]}</span></div></div>
|
||||
</section>
|
||||
|
||||
<section className="image25-workspace" id="comparison" aria-label={t.compare}>
|
||||
<div className="image25-comparison-panel">
|
||||
<div className="image25-notice"><span><Info size={15} />{notice}</span><button type="button" className="image25-icon-button" onClick={() => setModal('images')} aria-label={t.enlarge} title={t.enlarge}><Expand size={17} /></button></div>
|
||||
<div className={`image25-canvas image25-canvas-${view}${result ? ' image25-canvas-real' : ''}`} style={{ '--split': `${position}%` }}>
|
||||
{picture(beforeLabel, 'before')}
|
||||
{picture(afterLabel, 'after')}
|
||||
{view === 'slider' && <>
|
||||
<div className="image25-divider" aria-hidden="true"><span><ChevronsLeftRight size={24} /></span></div>
|
||||
<input className="image25-range" aria-label={t.sliderLabel} aria-valuetext={`${position}%`} type="range" min="0" max="100" value={position} onChange={event => setPosition(Number(event.target.value))} />
|
||||
</>}
|
||||
</div>
|
||||
<div className="image25-comparison-controls"><div className="image25-view-switch" role="group" aria-label={language === 'zh' ? '对比方式' : 'Comparison layout'}><button type="button" aria-pressed={view === 'side'} onClick={() => setView('side')}><Columns2 size={17} />{t.sideBySide}</button><button type="button" aria-pressed={view === 'slider'} onClick={() => setView('slider')}><ChevronsLeftRight size={17} />{t.slider}</button></div><p><Info size={16} />{result ? t.testHelp : t.sliderHelp}</p></div>
|
||||
</div>
|
||||
|
||||
<aside className="image25-prompt-panel" aria-label={t.shared}>
|
||||
<div className="image25-prompt-heading"><h3>{t.shared}</h3><Copy size={17} /></div>
|
||||
<textarea aria-label={t.promptLabel} readOnly value={item.prompt} spellCheck={false} />
|
||||
<button type="button" className="image25-copy" onClick={copyPrompt}>{copyState === 'copied' ? <Check size={17} /> : <Copy size={17} />}{copyState === 'copied' ? t.copied : t.copy}</button>
|
||||
<span className="image25-copy-status" role="status">{copyState === 'failed' ? t.copyFailed : copyState === 'copied' ? t.copied : ''}</span>
|
||||
{result ? <section className="image25-result-info" aria-label={t.thisRun}><h3>{t.thisRun}</h3><p className="image25-result-status"><Check size={17} />{t.completed}</p><p>{result.summary[language]}</p><small>{result.modelNote[language]}</small></section> : <fieldset className="image25-models"><legend>{t.choose}</legend>{['sunburst', 'flare'].map(value => <label key={value} className="image25-model-option"><input type="radio" name="image25-model" value={value} checked={model === value} onChange={() => setModel(value)} />{value === 'sunburst' ? <Sun size={34} /> : <Zap size={34} />}<span><strong>{value === 'sunburst' ? 'Sunburst' : 'Flare'}</strong><small>{t[value]}</small></span></label>)}</fieldset>}
|
||||
<button type="button" className="image25-parameters" onClick={() => setModal('params')}><Settings2 size={19} />{t.params}<ArrowUpRight size={15} /></button>
|
||||
<div className="image25-next"><select className="image25-case-select" aria-label={t.chooseCase} value={item.id} onChange={event => selectCase(comparisonCases.findIndex(entry => entry.id === event.target.value))}>{comparisonCases.map((entry, index) => <option key={entry.id} value={entry.id}>{String(index + 1).padStart(2, '0')} / {String(comparisonCases.length).padStart(2, '0')} · {entry.title[language]}{entry.result ? '' : ` · ${t.demo}`}</option>)}</select><button className="image25-button" type="button" onClick={nextCase}>{t.next}<ArrowRight size={19} /></button></div>
|
||||
</aside>
|
||||
</section>
|
||||
|
||||
<div className="image25-context"><p><Info size={16} />{explanation}</p><p>{t.focus}:{item.focus[language]}</p>{item.sourceUrl ? <a href={item.sourceUrl} target="_blank" rel="noreferrer">{t.source}:{item.source[language]}<ArrowUpRight size={14} /></a> : <span>{t.source}:{item.source[language]}</span>}</div>
|
||||
</main>
|
||||
<footer className="image25-footer"><div><WandSparkles size={19} /><strong>{t.footer}</strong><span>{t.docsDate}</span></div><p>{t.footerNote}</p><a href="/">{t.back}<ArrowRight size={15} /></a></footer>
|
||||
|
||||
<dialog className={`image25-dialog ${modal === 'images' ? 'image25-dialog-images' : ''}`} ref={dialogRef} aria-labelledby="image25-dialog-title" onCancel={() => setModal(null)} onClick={event => { if (event.target === event.currentTarget) setModal(null); }}>
|
||||
<div className="image25-dialog-inner"><header><h2 id="image25-dialog-title">{modal === 'images' ? item.title[language] : t.params}</h2><button autoFocus type="button" className="image25-icon-button" onClick={() => setModal(null)} aria-label={t.close}><X size={23} /></button></header>
|
||||
{modal === 'images' ? <><p className="image25-modal-notice">{notice}</p><div className="image25-enlarged">{picture(beforeLabel, 'before')}{picture(afterLabel, 'after')}</div></> : result ? <>
|
||||
<p className="image25-modal-notice">{explanation}</p><dl>{result.parameters[language].map(row => <div key={row.label}><dt>{row.label}</dt><dd>{row.value}</dd></div>)}</dl><p className="image25-methodology">{result.modelNote[language]}</p>
|
||||
</> : <>
|
||||
<p className="image25-modal-notice">{t.demoExplanation}</p><dl><div><dt>{t.status}</dt><dd>{t.pending}</dd></div><div><dt>{t.model}</dt><dd>gpt-image-2<br />gpt-image-2.5-{model}</dd></div><div><dt>{t.settings}</dt><dd>{t.notRecorded}</dd></div><div><dt>{t.source}</dt><dd>{item.source[language]}</dd></div></dl><p className="image25-methodology">{t.methodology}</p><a className="image25-doc-link" href={modelDocs[model]} target="_blank" rel="noreferrer">{t.modelDetails}<ArrowUpRight size={16} /></a>
|
||||
</>}
|
||||
</div>
|
||||
</dialog>
|
||||
</div>;
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
import rioImage from '../assets/image25-case527-run1.png';
|
||||
import watercolorImage from '../assets/image25-case523-run1.png';
|
||||
import iconImage from '../assets/image25-case510-run1.png';
|
||||
import rioInput from '../../docs/design/gpt-image-2-5/case527-test-input.json';
|
||||
import watercolorInput from '../../docs/design/gpt-image-2-5/case523-test-input.json';
|
||||
import iconInput from '../../docs/design/gpt-image-2-5/case510-test-input.json';
|
||||
import rioRecord from '../../docs/design/gpt-image-2-5/case527-test-record.json';
|
||||
import watercolorRecord from '../../docs/design/gpt-image-2-5/case523-test-record.json';
|
||||
import iconRecord from '../../docs/design/gpt-image-2-5/case510-test-record.json';
|
||||
|
||||
function recreation(input, record, image, content) {
|
||||
const dimensions = value => `${value.width} × ${value.height}`;
|
||||
return {
|
||||
id: `gallery-${input.caseId}-test`,
|
||||
title: content.title,
|
||||
prompt: input.prompt,
|
||||
image: `/images/case${input.caseId}.jpg`,
|
||||
alt: { zh: `图库原图:${input.title}`, en: `Gallery original: ${content.title.en}` },
|
||||
source: { zh: `案例 #${input.caseId} · ${content.sourceLabel}`, en: `Case #${input.caseId} · ${content.sourceLabel}` },
|
||||
sourceUrl: input.source,
|
||||
focus: content.focus,
|
||||
result: {
|
||||
caseId: input.caseId,
|
||||
image,
|
||||
label: { zh: 'GPT 2.5', en: 'GPT 2.5' },
|
||||
alt: { zh: `本次生成:${input.title}`, en: `New generation: ${content.title.en}` },
|
||||
summary: content.summary,
|
||||
modelNote: {
|
||||
zh: '本次使用 Codex 内置生图。工具未返回具体型号、质量档位或费用。',
|
||||
en: 'Generated with the built-in Codex image tool. The exact model, quality setting and cost were not returned.'
|
||||
},
|
||||
parameters: {
|
||||
zh: [
|
||||
{ label: '生成日期', value: record.date },
|
||||
{ label: '输入', value: `站内案例 #${input.caseId} 完整 Prompt;未改写;无参考图` },
|
||||
{ label: '样本', value: '首次生成 1 张;保留原始结果' },
|
||||
{ label: '原图尺寸', value: dimensions(record.sourceDimensions) },
|
||||
{ label: '本次输出', value: dimensions(record.outputDimensions) },
|
||||
{ label: '调用等待', value: `约 ${record.approximateCallWallClockSeconds} 秒(含队列与传输)` },
|
||||
{ label: '模型与质量档位', value: 'Codex 内置生图;具体 ID 与档位未返回' },
|
||||
{ label: '费用', value: '工具未返回' },
|
||||
{ label: '原图生成条件', value: '来源为站内案例;原始模型 ID、输入与设置未独立核验' }
|
||||
],
|
||||
en: [
|
||||
{ label: 'Date', value: record.date },
|
||||
{ label: 'Input', value: `Full case #${input.caseId} gallery prompt; unchanged; no reference image` },
|
||||
{ label: 'Sample', value: 'One first-run image; original output retained' },
|
||||
{ label: 'Original size', value: dimensions(record.sourceDimensions) },
|
||||
{ label: 'New output', value: dimensions(record.outputDimensions) },
|
||||
{ label: 'Call wait', value: `About ${record.approximateCallWallClockSeconds} s, including queueing and transfer` },
|
||||
{ label: 'Model and quality', value: 'Built-in Codex image tool; exact ID and quality not returned' },
|
||||
{ label: 'Cost', value: 'Not returned' },
|
||||
{ label: 'Original conditions', value: 'Existing gallery case; original model ID, inputs and settings not independently verified' }
|
||||
]
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export const additionalCases = [
|
||||
recreation(rioInput, rioRecord, rioImage, {
|
||||
title: { zh: '里约纸雕 · 旅行海报', en: 'Rio diorama · Travel poster' },
|
||||
sourceLabel: '@john_my07',
|
||||
focus: { zh: '立体层次、地标、票据文字与纸张质感', en: 'Spatial layers, landmarks, ticket lettering and paper texture' },
|
||||
summary: {
|
||||
zh: '票据、基督像、黄车与纸质底座完整;街道立面更突出,周边注记更密集。',
|
||||
en: 'The ticket, statue, yellow taxi and miniature base are present. Street facades are more prominent and surrounding notes are denser.'
|
||||
}
|
||||
}),
|
||||
recreation(watercolorInput, watercolorRecord, watercolorImage, {
|
||||
title: { zh: '曼哈顿公园 · 水彩插画', en: 'Manhattan park · Watercolor' },
|
||||
sourceLabel: '@Taaruk_',
|
||||
focus: { zh: '水彩笔触、前后景层次、人物与无字约束', en: 'Watercolor texture, scene depth, people and the no-text constraint' },
|
||||
summary: {
|
||||
zh: '石桥与池塘占据更醒目的前景,树木覆盖更满;保留了无字的水彩与钢笔风格。',
|
||||
en: 'The bridge and pond occupy a more prominent foreground, with denser trees. The watercolor-and-ink style stays free of visible text.'
|
||||
}
|
||||
}),
|
||||
recreation(iconInput, iconRecord, iconImage, {
|
||||
title: { zh: 'Bichon Shop · 应用图标', en: 'Bichon Shop · App icon' },
|
||||
sourceLabel: '@iamaiistudio',
|
||||
focus: { zh: '圆角轮廓、留白、毛发材质与品牌文字', en: 'Rounded contour, padding, fur texture and brand lettering' },
|
||||
summary: {
|
||||
zh: '保留单个圆角图标与白底留白,卷毛与纸袋绳把更细;底色和品牌字体明显变化。',
|
||||
en: 'One rounded icon and white padding are retained, with detailed curls and rope handles. The background color and brand lettering change.'
|
||||
}
|
||||
})
|
||||
];
|
||||
@@ -0,0 +1,70 @@
|
||||
import mug from '../assets/image25-demo-mug.png';
|
||||
import { realCases } from './realCases';
|
||||
|
||||
// Real recreations carry their own result image and generation record.
|
||||
// The remaining illustrations are shared by both panels and labeled as UI demos.
|
||||
export const comparisonCases = [
|
||||
...realCases,
|
||||
{
|
||||
id: 'ceramic-mug',
|
||||
title: { zh: '陶瓷杯 · 商品摄影', en: 'Ceramic mug · Product photography' },
|
||||
prompt: '米色陶瓷杯,放在木桌上,柔和自然光,商业产品摄影。',
|
||||
image: mug,
|
||||
alt: { zh: '木桌上的米色斑点陶瓷杯,杯柄朝右,背景为虚化绿植', en: 'A beige speckled ceramic mug with its handle on the right, on a wooden table beside a blurred plant' },
|
||||
source: { zh: '专区原创示意素材', en: 'Illustration made for this page' },
|
||||
sourceUrl: '',
|
||||
focus: { zh: '材质、光线、构图与指令遵循', en: 'Material, light, composition, and prompt adherence' }
|
||||
},
|
||||
{
|
||||
"id": "gallery-531",
|
||||
"sourceCaseId": 531,
|
||||
"title": {
|
||||
"zh": "旅行海报 · 场景与文字",
|
||||
"en": "Travel poster · Scene & typography"
|
||||
},
|
||||
"prompt": "Create a luxurious, dreamy country travel-art collection in the exact visual language of an elegant premium tourism campaign: a large transparent crystal/glass architectural frame or arched glass display standing on a glossy reflective surface, containing a highly detailed cinematic illustration of the destination. For [COUNTRY], feature its most iconic landmarks, historic architecture, distinctive landscapes, local transportation, cultural elements, national flag, flowers and recognizable scenery arranged as one seamless poetic panorama. Use warm golden-hour sunlight, soft atmospheric haze, pastel cream, champagne, muted blue and sage tones, delicate clouds, subtle birds, realistic glass refraction and rainbow prism highlights along the edges. Create a perfect mirror reflection beneath the glass structure, extending the entire composition downward with beautifully softened reflections. Add elegant editorial typography at the top reading “[COUNTRY]”, with smaller refined text “THE SOUL OF [COUNTRY]” and “A JOURNEY THROUGH TIME • 2026” beneath it. Sophisticated luxury travel magazine aesthetic, photorealistic yet painterly, cinematic depth, fine-art composition, extremely detailed architecture, serene atmosphere, premium advertising photography, symmetrical balanced framing, soft film grain, 8K, vertical 4:5, no clutter, no modern UI elements, no extra text.",
|
||||
"image": "/images/case531.jpg",
|
||||
"alt": {
|
||||
"zh": "水晶框国家旅行广告海报",
|
||||
"en": "An illustrated Italy travel poster in a crystal frame"
|
||||
},
|
||||
"source": {
|
||||
"zh": "原案例 #531 · @Taaruk_(仅作示意)",
|
||||
"en": "Original case #531 · @Taaruk_ (illustration only)"
|
||||
},
|
||||
"sourceUrl": "https://x.com/Taaruk_/status/2091391283063361558",
|
||||
"focus": {
|
||||
"zh": "场景完整性、文字排版与建筑细节",
|
||||
"en": "Scene completeness, typography, and architecture"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "gallery-526",
|
||||
"sourceCaseId": 526,
|
||||
"title": {
|
||||
"zh": "光影海报 · 构图与质感",
|
||||
"en": "Light poster · Composition & texture"
|
||||
},
|
||||
"prompt": "从全黑剧场开始,像切标本一样用六片真实体积激光把空间分层。光面必须有明确起点、透视和薄雾中的厚度,人物站在交汇点,透明道具折射出一小束异色光扇。构图沿左下至右上的对角线推进,脸只用一道克制边光揭示;标题与其中一片光面共享透视,小字留在纯黑负空间。每次替换主题与角色时,不得退化成夜店模板、HUD、霓虹城市或无物理来源的光线。",
|
||||
"image": "/images/case526.jpg",
|
||||
"alt": {
|
||||
"zh": "体积激光黑场海报",
|
||||
"en": "A person holding a transparent object between colored light beams"
|
||||
},
|
||||
"source": {
|
||||
"zh": "原案例 #526 · @zhidawang219555(仅作示意)",
|
||||
"en": "Original case #526 · @zhidawang219555 (illustration only)"
|
||||
},
|
||||
"sourceUrl": "https://x.com/zhidawang219555/status/2090246237094310178",
|
||||
"focus": {
|
||||
"zh": "光线逻辑、空间层次与文字布局",
|
||||
"en": "Light, spatial depth, and typography"
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
export const modelDocs = {
|
||||
sunburst: 'https://developers.openai.com/api/docs/models/gpt-image-2.5-sunburst',
|
||||
flare: 'https://developers.openai.com/api/docs/models/gpt-image-2.5-flare',
|
||||
guide: 'https://developers.openai.com/api/docs/guides/image-generation'
|
||||
};
|
||||
@@ -0,0 +1,6 @@
|
||||
import React from 'react';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import App from './App';
|
||||
import './styles.css';
|
||||
|
||||
createRoot(document.getElementById('root')).render(<App />);
|
||||
@@ -0,0 +1,246 @@
|
||||
:root {
|
||||
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
||||
color: #eef5ff;
|
||||
background: #060914;
|
||||
font-synthesis: none;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
--image25-muted: #b5c4db;
|
||||
--image25-line: #252e40;
|
||||
--image25-cyan: #50e7ff;
|
||||
}
|
||||
* { box-sizing: border-box; }
|
||||
body { margin: 0; min-width: 320px; }
|
||||
html { scroll-behavior: smooth; }
|
||||
button, textarea, select { font: inherit; }
|
||||
button, a, select, input { -webkit-tap-highlight-color: transparent; }
|
||||
button, select { cursor: pointer; }
|
||||
button, a, textarea, select, input { outline-offset: 5px; }
|
||||
:focus-visible { outline: 2px solid var(--image25-cyan); }
|
||||
a { color: inherit; text-decoration: none; }
|
||||
button { color: inherit; }
|
||||
button:disabled { cursor: default; }
|
||||
.image25-page { overflow-x: clip; }
|
||||
.image25-sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
|
||||
.image25-skip { position: fixed; z-index: 30; top: 12px; left: 12px; padding: 12px 18px; color: #060914; background: #50e7ff; clip-path: inset(50%); }
|
||||
.image25-skip:focus { clip-path: none; }
|
||||
.image25-header { width: min(1220px, calc(100% - 80px)); min-height: 74px; margin: auto; display: flex; align-items: center; justify-content: space-between; gap: 20px; }
|
||||
.image25-brand { display: inline-flex; gap: 10px; align-items: center; border: 1px solid var(--image25-line); border-radius: 8px; padding: 11px 14px; font-size: 17px; font-weight: 750; white-space: nowrap; }
|
||||
.image25-brand svg { color: var(--image25-cyan); }
|
||||
.image25-header nav { margin-left: auto; display: flex; gap: 3px; align-items: center; border: 1px solid var(--image25-line); padding: 4px 13px; border-radius: 8px; }
|
||||
.image25-header nav a { position: relative; padding: 9px 13px; white-space: nowrap; font-size: 15px; font-weight: 650; color: var(--image25-muted); }
|
||||
.image25-header nav a:hover { color: white; }
|
||||
.image25-header nav a[aria-current="page"] { color: var(--image25-cyan); }
|
||||
.image25-header nav a[aria-current="page"]::after { content: ''; position: absolute; bottom: -4px; right: 12px; left: 12px; height: 2px; background: var(--image25-cyan); }
|
||||
.image25-header-actions { display: flex; gap: 12px; align-items: center; }
|
||||
.image25-language { position: relative; display: flex; align-items: center; border: 1px solid var(--image25-line); border-radius: 8px; }
|
||||
.image25-language select { appearance: none; border: 0; border-radius: 8px; padding: 12px 30px 12px 14px; background: #0a1020; color: #eef5ff; font-weight: 600; }
|
||||
.image25-language svg { position: absolute; right: 9px; pointer-events: none; }
|
||||
.image25-button { border: 1px solid #86f7d0; border-radius: 8px; display: inline-flex; align-items: center; justify-content: center; gap: 12px; padding: 16px 28px; color: #04151b; background: linear-gradient(105deg, #38e0f2, #c3ff75); font-weight: 750; font-size: 17px; transition: filter .16s, transform .16s; }
|
||||
.image25-button:hover { filter: brightness(1.08); transform: translateY(-1px); }
|
||||
.image25-back { padding: 11px 17px; font-size: 15px; white-space: nowrap; }
|
||||
.image25-hero { position: relative; width: min(1220px, calc(100% - 80px)); margin: 0 auto; min-height: 380px; padding: 36px 0 15px; }
|
||||
.image25-hero-copy { position: relative; z-index: 1; max-width: 920px; }
|
||||
.image25-hero h1 { font-size: clamp(64px, 6.55vw, 91px); letter-spacing: -3.5px; line-height: 1.1; margin: 0; font-weight: 760; }
|
||||
.image25-hero h2 { margin: 8px 0 18px; font-size: clamp(33px, 3.6vw, 50px); line-height: 1.3; letter-spacing: -.9px; font-weight: 730; }
|
||||
.image25-intro { max-width: 830px; margin-top: 10px; }
|
||||
.image25-intro p { margin: 3px 0; color: #d2ddec; font-size: 17px; line-height: 1.7; }
|
||||
.image25-hero-actions { display: flex; align-items: center; gap: 33px; margin-top: 21px; }
|
||||
.image25-doc-link { display: inline-flex; align-items: center; gap: 8px; color: #a2ecf4; text-decoration: underline; text-underline-offset: 6px; font-size: 16px; }
|
||||
.image25-doc-link:hover { color: white; }
|
||||
.image25-hero-art { position: absolute; top: 26px; right: -24px; width: 365px; height: 330px; pointer-events: none; }
|
||||
.image25-hero-art > img { position: absolute; top: -30px; left: -190px; width: 125%; height: 125%; object-fit: cover; mask-image: radial-gradient(ellipse 70% 76% at 62% 50%, #000 32%, transparent 78%); }
|
||||
.image25-hero-art > div { position: absolute; top: 57px; left: 63px; right: 0; color: #b0cfdf; text-align: center; }
|
||||
.image25-hero-art p { font-size: 31px; letter-spacing: 3px; font-weight: 300; font-style: italic; margin: 12px 0 55px; line-height: 1.55; }
|
||||
.image25-hero-art span { font-size: 17px; line-height: 1.65; color: #9aafc6; letter-spacing: 2px; }
|
||||
.image25-workspace { display: grid; grid-template-columns: minmax(0, 1fr) 360px; align-items: stretch; gap: 9px; width: min(1390px, calc(100% - 80px)); margin: 0 auto; scroll-margin-top: 20px; }
|
||||
.image25-comparison-panel, .image25-prompt-panel { min-width: 0; border: 1px solid var(--image25-line); border-radius: 9px; background: #090f1be6; }
|
||||
.image25-comparison-panel { padding: 13px 17px 10px; }
|
||||
.image25-notice { display: flex; gap: 12px; align-items: center; justify-content: space-between; min-height: 32px; margin-bottom: 1px; color: #c9d5e7; font-size: 13px; }
|
||||
.image25-notice > span { display: inline-flex; align-items: center; gap: 7px; }
|
||||
.image25-icon-button { display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto; width: 32px; height: 32px; background: transparent; border: 0; border-radius: 6px; color: var(--image25-muted); }
|
||||
.image25-icon-button:hover { background: #202b3e; color: white; }
|
||||
.image25-canvas { position: relative; aspect-ratio: 12 / 7; isolation: isolate; overflow: hidden; background: #050910; border: 1px solid #2e3641; border-radius: 7px; }
|
||||
.image25-picture { margin: 0; min-width: 0; position: relative; background: #050910; overflow: hidden; }
|
||||
.image25-picture img { display: block; width: 100%; height: 100%; object-fit: contain; user-select: none; }
|
||||
.image25-canvas-slider .image25-picture { position: absolute; inset: 0; }
|
||||
.image25-canvas-slider .image25-picture-after { clip-path: inset(0 0 0 var(--split)); }
|
||||
.image25-model-label { position: absolute; top: 14px; left: 14px; border: 1px solid #a8bdd524; padding: 9px 14px; border-radius: 6px; background: #101722c9; color: #f1f5fb; backdrop-filter: blur(8px); font-size: 14px; line-height: 1.25; font-weight: 600; }
|
||||
.image25-picture-after .image25-model-label { right: 14px; left: auto; }
|
||||
.image25-demo-label { position: absolute; bottom: 12px; left: 13px; background: #0b101dcc; border: 1px solid #bcc5d12e; padding: 6px 12px; border-radius: 6px; font-size: 12px; color: #e1e7f0; }
|
||||
.image25-detail-link { z-index: 4; display: inline-flex; align-items: center; gap: 6px; color: #a2ecf4; min-height: 36px; }
|
||||
.image25-detail-link:hover { color: white; background: #123248; border-color: #50e7ff; }
|
||||
.image25-picture-after .image25-demo-label { left: auto; right: 13px; }
|
||||
.image25-divider { position: absolute; inset: 0 auto 0 var(--split); width: 2px; transform: translateX(-1px); background: #f5f8ffde; pointer-events: none; z-index: 2; }
|
||||
.image25-divider > span { position: absolute; left: 50%; top: 47%; transform: translate(-50%, -50%); width: 40px; height: 40px; border-radius: 50%; background: #f5f8ff; box-shadow: 0 2px 14px #0003; color: #111a28; display: grid; place-items: center; }
|
||||
.image25-range { appearance: none; position: absolute; z-index: 3; inset: 0; width: 100%; height: 100%; margin: 0; cursor: col-resize; opacity: 0; touch-action: pan-y; }
|
||||
.image25-canvas:has(.image25-range:focus-visible) { outline: 2px solid var(--image25-cyan); outline-offset: 4px; }
|
||||
.image25-canvas-side { display: grid; grid-template-columns: 1fr 1fr; gap: 2px; }
|
||||
.image25-canvas-side .image25-picture { height: 100%; }
|
||||
.image25-canvas-side .image25-model-label { left: 10px; right: auto; padding: 8px 10px; font-size: 12px; }
|
||||
.image25-comparison-controls { display: flex; align-items: center; justify-content: flex-end; gap: 45px; min-height: 58px; padding: 8px 0 0; }
|
||||
.image25-view-switch { display: flex; border: 1px solid #33425b; border-radius: 30px; padding: 0; flex-shrink: 0; }
|
||||
.image25-view-switch button { display: flex; align-items: center; gap: 8px; border: 1px solid transparent; border-radius: 30px; padding: 8px 17px; background: transparent; color: #c1ccdd; font-size: 14px; }
|
||||
.image25-view-switch button[aria-pressed="true"] { border-color: #40d6f0; color: #5de9fa; background: #123248; }
|
||||
.image25-comparison-controls p { display: flex; gap: 7px; align-items: center; margin: 0; color: #a6b8ce; font-size: 13px; }
|
||||
.image25-comparison-controls p svg { flex-shrink: 0; }
|
||||
.image25-prompt-panel { display: flex; flex-direction: column; padding: 23px 21px 24px; }
|
||||
.image25-prompt-heading { display: flex; align-items: center; gap: 10px; margin-bottom: 14px; }
|
||||
.image25-prompt-heading h3 { margin: 0; font-size: 17px; font-weight: 700; }
|
||||
.image25-prompt-heading svg { color: #bce5ed; }
|
||||
.image25-prompt-panel textarea { color: #dde7f8; background: #0b1120; border: 1px solid var(--image25-line); border-radius: 7px; padding: 13px; width: 100%; min-height: 90px; height: 90px; resize: vertical; font-size: 15px; line-height: 1.7; }
|
||||
.image25-copy { display: flex; justify-content: center; align-items: center; gap: 8px; background: #101726; border: 1px solid var(--image25-line); border-radius: 7px; width: 100%; padding: 10px; margin-top: 11px; font-size: 14px; }
|
||||
.image25-copy:hover { border-color: #678da8; }
|
||||
.image25-copy-status { min-height: 16px; margin-top: 4px; font-size: 12px; color: #a3edc4; }
|
||||
.image25-models { border: 0; border-top: 1px solid var(--image25-line); padding: 20px 0 0; margin: 6px 0 0; min-width: 0; }
|
||||
.image25-models legend { float: left; width: 100%; padding: 0; margin: 0 0 10px; font-weight: 650; font-size: 16px; }
|
||||
.image25-model-option { display: flex; align-items: center; position: relative; gap: 14px; padding: 16px; margin-top: 11px; min-height: 84px; border: 1px solid var(--image25-line); border-radius: 7px; background: #0a101d; cursor: pointer; }
|
||||
.image25-model-option:has(input:checked) { border-color: #63e1e9; background: #0d1c29; }
|
||||
.image25-model-option:has(input:focus-visible) { outline: 2px solid #50e7ff; outline-offset: 3px; }
|
||||
.image25-model-option > svg { flex-shrink: 0; color: #ccdae9; }
|
||||
.image25-model-option:has(input:checked) > svg { color: #50e7ff; }
|
||||
.image25-model-option input { order: 3; margin: 0 0 0 auto; accent-color: #55e6f6; width: 18px; height: 18px; flex-shrink: 0; }
|
||||
.image25-model-option strong { display: block; font-size: 17px; line-height: 1.4; }
|
||||
.image25-model-option small { display: block; font-size: 12px; color: #aebdd0; margin-top: 3px; }
|
||||
.image25-result-info { margin-top: 6px; padding-top: 20px; border-top: 1px solid var(--image25-line); }
|
||||
.image25-result-info h3 { margin: 0 0 14px; font-size: 16px; }
|
||||
.image25-result-info p { font-size: 14px; line-height: 1.8; color: #b5c4db; }
|
||||
.image25-result-info .image25-result-status { display: flex; gap: 7px; align-items: center; color: #89eecb; }
|
||||
.image25-result-info small { display: block; color: #93a8c0; font-size: 12px; line-height: 1.7; }
|
||||
.image25-parameters { display: flex; align-items: center; gap: 9px; border: 0; border-bottom: 1px solid var(--image25-line); padding: 20px 0; margin-top: 3px; width: 100%; color: #9bdae6; font-size: 14px; background: transparent; }
|
||||
.image25-parameters:hover { color: white; }
|
||||
.image25-next { margin-top: auto; padding-top: 14px; }
|
||||
.image25-next > span { display: block; font-size: 11px; color: #8f9fb4; margin-bottom: 9px; }
|
||||
.image25-case-select { display: block; width: 100%; min-width: 0; padding: 10px 9px; margin-bottom: 10px; border: 1px solid var(--image25-line); border-radius: 7px; background: #0b1120; color: #c8d8e8; font-size: 12px; }
|
||||
.image25-next .image25-button { width: 100%; padding: 14px; }
|
||||
.image25-context { width: min(1390px, calc(100% - 80px)); margin: 18px auto 40px; display: flex; flex-wrap: wrap; justify-content: space-between; gap: 10px 24px; font-size: 12px; color: #91a1ba; line-height: 1.6; }
|
||||
.image25-context p { display: flex; gap: 7px; align-items: center; margin: 0; }
|
||||
.image25-context p:first-child { width: 100%; }
|
||||
.image25-context svg { flex-shrink: 0; }
|
||||
.image25-context a { display: inline-flex; align-items: center; gap: 5px; text-decoration: underline; text-underline-offset: 3px; }
|
||||
.image25-footer { width: min(1220px, calc(100% - 80px)); margin: 0 auto; padding: 25px 0 35px; border-top: 1px solid var(--image25-line); display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 13px 20px; color: #9fb0c9; font-size: 12px; }
|
||||
.image25-footer > div { display: flex; align-items: center; gap: 9px; }
|
||||
.image25-footer > div > span { margin-left: 14px; }
|
||||
.image25-footer p { margin: 0; }
|
||||
.image25-footer a { display: inline-flex; align-items: center; gap: 5px; color: #c3d5e8; }
|
||||
.image25-dialog { color: #eef5ff; background: #0d1423; border: 1px solid #3b4b62; border-radius: 14px; padding: 0; width: min(620px, calc(100% - 32px)); max-height: 88dvh; }
|
||||
.image25-dialog::backdrop { background: #020610d9; backdrop-filter: blur(7px); }
|
||||
.image25-dialog-inner { padding: 25px; }
|
||||
.image25-dialog-inner > header { display: flex; align-items: center; justify-content: space-between; gap: 20px; }
|
||||
.image25-dialog h2 { margin: 0; font-size: 23px; }
|
||||
.image25-modal-notice { color: #bbccdf; font-size: 14px; line-height: 1.8; margin: 18px 0; }
|
||||
.image25-dialog dl { margin: 22px 0; }
|
||||
.image25-dialog dl > div { display: grid; grid-template-columns: 160px minmax(0, 1fr); border-top: 1px solid var(--image25-line); padding: 13px 0; gap: 15px; font-size: 13px; line-height: 1.6; }
|
||||
.image25-dialog dt { color: #9faec4; }
|
||||
.image25-dialog dd { margin: 0; overflow-wrap: anywhere; }
|
||||
.image25-methodology { font-size: 13px; line-height: 1.9; color: #b0c0d7; }
|
||||
.image25-dialog .image25-doc-link { font-size: 14px; }
|
||||
.image25-dialog-images { width: min(1350px, calc(100% - 32px)); }
|
||||
.image25-enlarged { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
|
||||
.image25-enlarged .image25-picture { border-radius: 8px; }
|
||||
.image25-enlarged .image25-picture img { max-height: 68dvh; }
|
||||
@media (min-width: 1500px) {
|
||||
.image25-hero { min-height: 410px; padding-top: 52px; }
|
||||
}
|
||||
@media (max-width: 1190px) {
|
||||
.image25-header { gap: 12px; }
|
||||
.image25-brand { font-size: 15px; padding: 10px; }
|
||||
.image25-header nav { padding-inline: 4px; }
|
||||
.image25-header nav a { padding-inline: 9px; }
|
||||
.image25-back { padding: 11px; font-size: 13px; }
|
||||
.image25-header-actions { gap: 8px; }
|
||||
.image25-hero-art { opacity: .5; right: -40px; }
|
||||
.image25-hero-copy { max-width: 760px; }
|
||||
.image25-hero h2 { font-size: 40px; }
|
||||
.image25-intro { max-width: 720px; }
|
||||
.image25-intro p { font-size: 15px; }
|
||||
.image25-workspace { grid-template-columns: minmax(0, 1fr) 300px; }
|
||||
.image25-prompt-panel { padding: 20px 17px; }
|
||||
.image25-comparison-controls { flex-wrap: wrap; justify-content: center; gap: 10px; padding: 14px 0 6px; }
|
||||
.image25-model-option { min-height: 76px; padding: 13px; gap: 10px; }
|
||||
.image25-model-option strong { font-size: 16px; }
|
||||
.image25-model-option small { font-size: 11px; }
|
||||
.image25-model-label { font-size: 12px; padding: 8px; left: 10px; }
|
||||
.image25-picture-after .image25-model-label { right: 10px; }
|
||||
}
|
||||
@media (max-width: 950px) {
|
||||
.image25-header { flex-wrap: wrap; padding: 13px 0; gap: 14px; }
|
||||
.image25-header nav { order: 3; width: 100%; justify-content: center; }
|
||||
.image25-header-actions { margin-left: auto; }
|
||||
.image25-hero { min-height: 345px; padding-top: 33px; }
|
||||
.image25-hero-art { display: none; }
|
||||
.image25-hero h1 { font-size: 68px; }
|
||||
.image25-hero h2 { font-size: 36px; }
|
||||
.image25-workspace { grid-template-columns: minmax(0, 1fr); gap: 16px; }
|
||||
.image25-comparison-controls { flex-wrap: nowrap; justify-content: space-between; }
|
||||
.image25-prompt-panel { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); column-gap: 24px; padding: 24px; }
|
||||
.image25-prompt-heading, .image25-prompt-panel textarea, .image25-copy, .image25-copy-status { grid-column: 1; }
|
||||
.image25-prompt-panel textarea { height: 110px; }
|
||||
.image25-models { grid-column: 2; grid-row: 1 / 5; padding: 0; border: 0; margin: 0; }
|
||||
.image25-result-info { grid-column: 2; grid-row: 1 / 5; padding: 0; border: 0; margin: 0; }
|
||||
.image25-model-option { clear: both; }
|
||||
.image25-next, .image25-parameters { grid-column: 1 / -1; }
|
||||
.image25-next { display: flex; gap: 20px; align-items: center; justify-content: space-between; }
|
||||
.image25-next > span { margin: 0; }
|
||||
.image25-case-select { flex: 1; margin: 0; width: auto; }
|
||||
.image25-next .image25-button { width: auto; min-width: 180px; }
|
||||
}
|
||||
@media (max-width: 600px) {
|
||||
.image25-header, .image25-hero, .image25-workspace, .image25-context, .image25-footer { width: calc(100% - 32px); }
|
||||
.image25-brand { font-size: 14px; gap: 7px; padding: 9px; }
|
||||
.image25-brand svg { width: 19px; }
|
||||
.image25-header { gap: 12px; }
|
||||
.image25-header-actions { gap: 7px; }
|
||||
.image25-language select { padding: 10px 27px 10px 9px; font-size: 12px; }
|
||||
.image25-back { display: none; }
|
||||
.image25-header nav a { font-size: 13px; padding: 7px 11px; }
|
||||
.image25-header nav { justify-content: space-between; padding-inline: 9px; }
|
||||
.image25-hero { min-height: 0; padding: 30px 0 27px; }
|
||||
.image25-hero h1 { font-size: clamp(37px, 9.5vw, 55px); letter-spacing: -1.6px; }
|
||||
.image25-hero h2 { font-size: clamp(22px, 5.6vw, 30px); line-height: 1.45; letter-spacing: -.5px; margin: 10px 0 15px; }
|
||||
.image25-intro p { font-size: 13px; line-height: 1.8; margin: 7px 0; }
|
||||
.image25-hero-actions { gap: 25px; margin-top: 20px; }
|
||||
.image25-hero-actions .image25-button { font-size: 14px; padding: 13px 18px; }
|
||||
.image25-doc-link { font-size: 13px; gap: 5px; }
|
||||
.image25-comparison-panel { padding: 9px 9px 12px; }
|
||||
.image25-notice { font-size: 10px; gap: 3px; }
|
||||
.image25-notice > span { gap: 4px; }
|
||||
.image25-notice svg { width: 13px; }
|
||||
.image25-canvas { aspect-ratio: 4 / 3; }
|
||||
.image25-model-label { font-size: 10px; left: 7px; top: 9px; padding: 6px; }
|
||||
.image25-picture-after .image25-model-label { right: 7px; }
|
||||
.image25-demo-label { font-size: 10px; padding: 4px 7px; bottom: 9px; left: 7px; }
|
||||
.image25-picture-after .image25-demo-label { right: 7px; }
|
||||
.image25-divider > span { height: 33px; width: 33px; top: 50%; }
|
||||
.image25-divider svg { width: 20px; }
|
||||
.image25-comparison-controls { flex-wrap: wrap; justify-content: center; gap: 11px; padding-top: 15px; }
|
||||
.image25-comparison-controls p { font-size: 11px; }
|
||||
.image25-view-switch button { font-size: 12px; padding: 8px 16px; }
|
||||
.image25-canvas-side { aspect-ratio: 12 / 7; }
|
||||
.image25-canvas-side .image25-model-label { top: 7px; left: 7px; right: auto; padding: 6px; font-size: 10px; }
|
||||
.image25-prompt-panel { display: flex; padding: 20px; }
|
||||
.image25-prompt-panel textarea { height: 98px; }
|
||||
.image25-models { border-top: 1px solid var(--image25-line); padding-top: 21px; margin-top: 9px; }
|
||||
.image25-result-info { border-top: 1px solid var(--image25-line); padding-top: 21px; margin-top: 9px; }
|
||||
.image25-model-option { padding: 14px; }
|
||||
.image25-model-option small { font-size: 12px; }
|
||||
.image25-next { display: block; }
|
||||
.image25-next > span { margin-bottom: 9px; }
|
||||
.image25-case-select { width: 100%; margin-bottom: 10px; }
|
||||
.image25-next .image25-button { width: 100%; }
|
||||
.image25-context { font-size: 11px; margin-bottom: 25px; }
|
||||
.image25-context p:first-child { align-items: flex-start; }
|
||||
.image25-context p:first-child svg { margin-top: 2px; }
|
||||
.image25-footer { gap: 14px; line-height: 1.7; }
|
||||
.image25-footer > div { flex-wrap: wrap; }
|
||||
.image25-footer > div > span { width: 100%; margin: 0; }
|
||||
.image25-dialog-inner { padding: 19px; }
|
||||
.image25-dialog h2 { font-size: 19px; }
|
||||
.image25-dialog dl > div { grid-template-columns: 1fr; gap: 5px; }
|
||||
.image25-enlarged { grid-template-columns: 1fr; }
|
||||
.image25-enlarged .image25-picture img { max-height: 60dvh; }
|
||||
}
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
html { scroll-behavior: auto; }
|
||||
*, *::before, *::after { transition: none !important; }
|
||||
}
|
||||
@@ -3784,6 +3784,22 @@ function App() {
|
||||
});
|
||||
}, [siteData, styleLibrary]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!siteData) return;
|
||||
const requestedCase = new URLSearchParams(window.location.search).get('case');
|
||||
if (!/^[1-9]\d*$/.test(requestedCase || '')) return;
|
||||
const item = siteData.cases.find((caseItem) => Number(caseItem.id) === Number(requestedCase));
|
||||
if (item) setPreview({ type: 'case', item });
|
||||
}, [siteData]);
|
||||
|
||||
function closePreview() {
|
||||
setPreview(null);
|
||||
const url = new URL(window.location.href);
|
||||
if (!url.searchParams.has('case')) return;
|
||||
url.searchParams.delete('case');
|
||||
window.history.replaceState({}, '', `${url.pathname}${url.search}${url.hash}`);
|
||||
}
|
||||
|
||||
function openAuth() {
|
||||
setAuthErrorCode('');
|
||||
setAuthOpen(true);
|
||||
@@ -4058,6 +4074,7 @@ function App() {
|
||||
<div className="topbarControls">
|
||||
<nav>
|
||||
<a href="#gallery">{t.navCases}</a>
|
||||
<a href="/gpt-image-2-5/">{language === 'zh' ? '2.5 专区' : 'Image 2.5'}</a>
|
||||
<a href="#templates">{t.navTemplates}</a>
|
||||
<a href="#agent-skill">{t.navSkill}</a>
|
||||
<CommunityNavItem language={language} />
|
||||
@@ -4221,7 +4238,7 @@ function App() {
|
||||
apimartPriceMeta={apimartPriceMeta}
|
||||
favorite={preview?.type === 'case' ? favoriteCaseIds.has(preview.item.id) : false}
|
||||
favoriteBusy={preview?.type === 'case' && favoriteBusyId === preview.item.id}
|
||||
onClose={() => setPreview(null)}
|
||||
onClose={closePreview}
|
||||
onCopyText={copyText}
|
||||
onToggleFavorite={handleToggleFavorite}
|
||||
onAuthRequired={openAuth}
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
import { defineConfig } from 'vite';
|
||||
import react from '@vitejs/plugin-react';
|
||||
import { localVercelApi } from './scripts/vite-local-api.mjs';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [localVercelApi(), react()],
|
||||
publicDir: 'data',
|
||||
build: {
|
||||
outDir: 'dist',
|
||||
sourcemap: false
|
||||
sourcemap: false,
|
||||
rollupOptions: {
|
||||
input: {
|
||||
gallery: fileURLToPath(new URL('./index.html', import.meta.url)),
|
||||
image25: fileURLToPath(new URL('./gpt-image-2-5/index.html', import.meta.url))
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||